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 U_NAMESPACE_USE 26 27 28 // maps our unit element to the corresponding ICU unit 29 static const UCalendarDateFields skUnitMap[] = { 30 UCAL_YEAR, 31 UCAL_MONTH, 32 UCAL_WEEK_OF_MONTH, 33 UCAL_DAY_OF_WEEK, 34 UCAL_HOUR_OF_DAY, 35 UCAL_MINUTE, 36 UCAL_SECOND, 37 }; 38 39 40 BDurationFormat::BDurationFormat(const BLanguage& language, 41 const BFormattingConventions& conventions, 42 const BString& separator, const time_unit_style style) 43 : 44 Inherited(language, conventions), 45 fSeparator(separator), 46 fTimeUnitFormat(language, conventions, style) 47 { 48 UErrorCode icuStatus = U_ZERO_ERROR; 49 fCalendar = new GregorianCalendar(icuStatus); 50 if (fCalendar == NULL) { 51 fInitStatus = B_NO_MEMORY; 52 return; 53 } 54 } 55 56 57 BDurationFormat::BDurationFormat(const BString& separator, 58 const time_unit_style style) 59 : 60 Inherited(), 61 fSeparator(separator), 62 fTimeUnitFormat(style) 63 { 64 UErrorCode icuStatus = U_ZERO_ERROR; 65 fCalendar = new GregorianCalendar(icuStatus); 66 if (fCalendar == NULL) { 67 fInitStatus = B_NO_MEMORY; 68 return; 69 } 70 } 71 72 73 BDurationFormat::BDurationFormat(const BDurationFormat& other) 74 : 75 Inherited(other), 76 fSeparator(other.fSeparator), 77 fTimeUnitFormat(other.fTimeUnitFormat), 78 fCalendar(other.fCalendar != NULL 79 ? new GregorianCalendar(*other.fCalendar) : NULL) 80 { 81 if (fCalendar == NULL && other.fCalendar != NULL) 82 fInitStatus = B_NO_MEMORY; 83 } 84 85 86 BDurationFormat::~BDurationFormat() 87 { 88 delete fCalendar; 89 } 90 91 92 void 93 BDurationFormat::SetSeparator(const BString& separator) 94 { 95 fSeparator = separator; 96 } 97 98 99 status_t 100 BDurationFormat::SetTimeZone(const BTimeZone* timeZone) 101 { 102 if (fCalendar == NULL) 103 return B_NO_INIT; 104 105 BTimeZone::Private zonePrivate; 106 if (timeZone == NULL) { 107 BTimeZone defaultTimeZone; 108 status_t result 109 = BLocaleRoster::Default()->GetDefaultTimeZone(&defaultTimeZone); 110 if (result != B_OK) 111 return result; 112 zonePrivate.SetTo(&defaultTimeZone); 113 } else 114 zonePrivate.SetTo(timeZone); 115 116 TimeZone* icuTimeZone = zonePrivate.ICUTimeZone(); 117 if (icuTimeZone != NULL) 118 fCalendar->setTimeZone(*icuTimeZone); 119 120 return B_OK; 121 } 122 123 124 status_t 125 BDurationFormat::Format(BString& buffer, const bigtime_t startValue, 126 const bigtime_t stopValue) const 127 { 128 UErrorCode icuStatus = U_ZERO_ERROR; 129 fCalendar->setTime((UDate)startValue / 1000, icuStatus); 130 if (!U_SUCCESS(icuStatus)) 131 return B_ERROR; 132 133 UDate stop = (UDate)stopValue / 1000; 134 bool needSeparator = false; 135 for (int unit = 0; unit <= B_TIME_UNIT_LAST; ++unit) { 136 int delta 137 = fCalendar->fieldDifference(stop, skUnitMap[unit], icuStatus); 138 if (!U_SUCCESS(icuStatus)) 139 return B_ERROR; 140 141 if (delta != 0) { 142 if (needSeparator) 143 buffer.Append(fSeparator); 144 else 145 needSeparator = true; 146 status_t status = fTimeUnitFormat.Format(buffer, delta, 147 (time_unit_element)unit); 148 if (status != B_OK) 149 return status; 150 } 151 } 152 153 return B_OK; 154 } 155