1 /* 2 * Copyright 2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Oliver Tappe <zooey@hirschkaefer.de> 7 */ 8 9 10 #include <unicode/uversion.h> 11 #include <DurationFormat.h> 12 13 #include <new> 14 15 #include <unicode/gregocal.h> 16 #include <unicode/utypes.h> 17 18 #include <Locale.h> 19 #include <LocaleRoster.h> 20 #include <TimeZone.h> 21 22 #include <TimeZonePrivate.h> 23 24 25 // maps our unit element to the corresponding ICU unit 26 static const UCalendarDateFields skUnitMap[] = { 27 UCAL_YEAR, 28 UCAL_MONTH, 29 UCAL_WEEK_OF_MONTH, 30 UCAL_DAY_OF_WEEK, 31 UCAL_HOUR_OF_DAY, 32 UCAL_MINUTE, 33 UCAL_SECOND, 34 }; 35 36 37 BDurationFormat::BDurationFormat(const BLanguage& language, 38 const BFormattingConventions& conventions, 39 const BString& separator, const time_unit_style style) 40 : 41 Inherited(language, conventions), 42 fSeparator(separator), 43 fTimeUnitFormat(language, conventions, style) 44 { 45 UErrorCode icuStatus = U_ZERO_ERROR; 46 fCalendar = new GregorianCalendar(icuStatus); 47 if (fCalendar == NULL) { 48 fInitStatus = B_NO_MEMORY; 49 return; 50 } 51 } 52 53 54 BDurationFormat::BDurationFormat(const BString& separator, 55 const time_unit_style style) 56 : 57 Inherited(), 58 fSeparator(separator), 59 fTimeUnitFormat(style) 60 { 61 UErrorCode icuStatus = U_ZERO_ERROR; 62 fCalendar = new GregorianCalendar(icuStatus); 63 if (fCalendar == NULL) { 64 fInitStatus = B_NO_MEMORY; 65 return; 66 } 67 } 68 69 70 BDurationFormat::BDurationFormat(const BDurationFormat& other) 71 : 72 Inherited(other), 73 fSeparator(other.fSeparator), 74 fTimeUnitFormat(other.fTimeUnitFormat), 75 fCalendar(other.fCalendar != NULL 76 ? new GregorianCalendar(*other.fCalendar) : NULL) 77 { 78 if (fCalendar == NULL && other.fCalendar != NULL) 79 fInitStatus = B_NO_MEMORY; 80 } 81 82 83 BDurationFormat::~BDurationFormat() 84 { 85 delete fCalendar; 86 } 87 88 89 void 90 BDurationFormat::SetSeparator(const BString& separator) 91 { 92 fSeparator = separator; 93 } 94 95 96 status_t 97 BDurationFormat::SetTimeZone(const BTimeZone* timeZone) 98 { 99 if (fCalendar == NULL) 100 return B_NO_INIT; 101 102 BTimeZone::Private zonePrivate; 103 if (timeZone == NULL) { 104 BTimeZone defaultTimeZone; 105 status_t result 106 = BLocaleRoster::Default()->GetDefaultTimeZone(&defaultTimeZone); 107 if (result != B_OK) 108 return result; 109 zonePrivate.SetTo(&defaultTimeZone); 110 } else 111 zonePrivate.SetTo(timeZone); 112 113 TimeZone* icuTimeZone = zonePrivate.ICUTimeZone(); 114 if (icuTimeZone != NULL) 115 fCalendar->setTimeZone(*icuTimeZone); 116 117 return B_OK; 118 } 119 120 121 status_t 122 BDurationFormat::Format(BString& buffer, const bigtime_t startValue, 123 const bigtime_t stopValue) const 124 { 125 UErrorCode icuStatus = U_ZERO_ERROR; 126 fCalendar->setTime((UDate)startValue / 1000, icuStatus); 127 if (!U_SUCCESS(icuStatus)) 128 return B_ERROR; 129 130 UDate stop = (UDate)stopValue / 1000; 131 bool needSeparator = false; 132 for (int unit = 0; unit <= B_TIME_UNIT_LAST; ++unit) { 133 int delta 134 = fCalendar->fieldDifference(stop, skUnitMap[unit], icuStatus); 135 if (!U_SUCCESS(icuStatus)) 136 return B_ERROR; 137 138 if (delta != 0) { 139 if (needSeparator) 140 buffer.Append(fSeparator); 141 else 142 needSeparator = true; 143 status_t status = fTimeUnitFormat.Format(buffer, delta, 144 (time_unit_element)unit); 145 if (status != B_OK) 146 return status; 147 } 148 } 149 150 return B_OK; 151 } 152