1 /* 2 * Copyright 2010-2014, 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 #include <TimeFormat.h> 10 11 #include <AutoDeleter.h> 12 #include <Autolock.h> 13 #include <DateTime.h> 14 #include <FormattingConventionsPrivate.h> 15 #include <LanguagePrivate.h> 16 #include <TimeZone.h> 17 18 #include <ICUWrapper.h> 19 20 #include <unicode/datefmt.h> 21 #include <unicode/smpdtfmt.h> 22 23 #include <vector> 24 25 26 BTimeFormat::BTimeFormat() 27 : BFormat() 28 { 29 } 30 31 32 BTimeFormat::BTimeFormat(const BLanguage& language, 33 const BFormattingConventions& conventions) 34 : BFormat(language, conventions) 35 { 36 } 37 38 39 BTimeFormat::BTimeFormat(const BTimeFormat &other) 40 : BFormat(other) 41 { 42 } 43 44 45 BTimeFormat::~BTimeFormat() 46 { 47 } 48 49 50 void 51 BTimeFormat::SetTimeFormat(BTimeFormatStyle style, 52 const BString& format) 53 { 54 fConventions.SetExplicitTimeFormat(style, format); 55 } 56 57 58 // #pragma mark - Formatting 59 60 61 ssize_t 62 BTimeFormat::Format(char* string, size_t maxSize, time_t time, 63 BTimeFormatStyle style) const 64 { 65 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 66 if (timeFormatter.Get() == NULL) 67 return B_NO_MEMORY; 68 69 UnicodeString icuString; 70 timeFormatter->format((UDate)time * 1000, icuString); 71 72 CheckedArrayByteSink stringConverter(string, maxSize); 73 icuString.toUTF8(stringConverter); 74 75 if (stringConverter.Overflowed()) 76 return B_BAD_VALUE; 77 78 return stringConverter.NumberOfBytesWritten(); 79 } 80 81 82 status_t 83 BTimeFormat::Format(BString& string, const time_t time, 84 const BTimeFormatStyle style, const BTimeZone* timeZone) const 85 { 86 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 87 if (timeFormatter.Get() == NULL) 88 return B_NO_MEMORY; 89 90 if (timeZone != NULL) { 91 ObjectDeleter<TimeZone> icuTimeZone( 92 TimeZone::createTimeZone(timeZone->ID().String())); 93 if (icuTimeZone.Get() == NULL) 94 return B_NO_MEMORY; 95 timeFormatter->setTimeZone(*icuTimeZone.Get()); 96 } 97 98 UnicodeString icuString; 99 timeFormatter->format((UDate)time * 1000, icuString); 100 101 string.Truncate(0); 102 BStringByteSink stringConverter(&string); 103 icuString.toUTF8(stringConverter); 104 105 return B_OK; 106 } 107 108 109 status_t 110 BTimeFormat::Format(BString& string, int*& fieldPositions, int& fieldCount, 111 time_t time, BTimeFormatStyle style) const 112 { 113 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 114 if (timeFormatter.Get() == NULL) 115 return B_NO_MEMORY; 116 117 fieldPositions = NULL; 118 UErrorCode error = U_ZERO_ERROR; 119 icu::FieldPositionIterator positionIterator; 120 UnicodeString icuString; 121 timeFormatter->format((UDate)time * 1000, icuString, &positionIterator, 122 error); 123 124 if (error != U_ZERO_ERROR) 125 return B_BAD_VALUE; 126 127 icu::FieldPosition field; 128 std::vector<int> fieldPosStorage; 129 fieldCount = 0; 130 while (positionIterator.next(field)) { 131 fieldPosStorage.push_back(field.getBeginIndex()); 132 fieldPosStorage.push_back(field.getEndIndex()); 133 fieldCount += 2; 134 } 135 136 fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 137 138 for (int i = 0 ; i < fieldCount ; i++ ) 139 fieldPositions[i] = fieldPosStorage[i]; 140 141 string.Truncate(0); 142 BStringByteSink stringConverter(&string); 143 icuString.toUTF8(stringConverter); 144 145 return B_OK; 146 } 147 148 149 status_t 150 BTimeFormat::GetTimeFields(BDateElement*& fields, int& fieldCount, 151 BTimeFormatStyle style) const 152 { 153 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 154 if (timeFormatter.Get() == NULL) 155 return B_NO_MEMORY; 156 157 fields = NULL; 158 UErrorCode error = U_ZERO_ERROR; 159 icu::FieldPositionIterator positionIterator; 160 UnicodeString icuString; 161 time_t now; 162 timeFormatter->format((UDate)time(&now) * 1000, icuString, 163 &positionIterator, error); 164 165 if (error != U_ZERO_ERROR) 166 return B_BAD_VALUE; 167 168 icu::FieldPosition field; 169 std::vector<int> fieldPosStorage; 170 fieldCount = 0; 171 while (positionIterator.next(field)) { 172 fieldPosStorage.push_back(field.getField()); 173 fieldCount ++; 174 } 175 176 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 177 178 for (int i = 0 ; i < fieldCount ; i++ ) { 179 switch (fieldPosStorage[i]) { 180 case UDAT_HOUR_OF_DAY1_FIELD: 181 case UDAT_HOUR_OF_DAY0_FIELD: 182 case UDAT_HOUR1_FIELD: 183 case UDAT_HOUR0_FIELD: 184 fields[i] = B_DATE_ELEMENT_HOUR; 185 break; 186 case UDAT_MINUTE_FIELD: 187 fields[i] = B_DATE_ELEMENT_MINUTE; 188 break; 189 case UDAT_SECOND_FIELD: 190 fields[i] = B_DATE_ELEMENT_SECOND; 191 break; 192 case UDAT_AM_PM_FIELD: 193 fields[i] = B_DATE_ELEMENT_AM_PM; 194 break; 195 default: 196 fields[i] = B_DATE_ELEMENT_INVALID; 197 break; 198 } 199 } 200 201 return B_OK; 202 } 203 204 205 status_t 206 BTimeFormat::Parse(BString source, BTimeFormatStyle style, BTime& output) 207 { 208 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 209 if (timeFormatter.Get() == NULL) 210 return B_NO_MEMORY; 211 212 // If no timezone is specified in the time string, assume GMT 213 timeFormatter->setTimeZone(*icu::TimeZone::getGMT()); 214 215 ParsePosition p(0); 216 UDate date = timeFormatter->parse(UnicodeString::fromUTF8(source.String()), 217 p); 218 219 output.SetTime(0, 0, 0); 220 output.AddMilliseconds(date); 221 222 return B_OK; 223 } 224 225 226 DateFormat* 227 BTimeFormat::_CreateTimeFormatter(const BTimeFormatStyle style) const 228 { 229 Locale* icuLocale 230 = fConventions.UseStringsFromPreferredLanguage() 231 ? BLanguage::Private(&fLanguage).ICULocale() 232 : BFormattingConventions::Private(&fConventions).ICULocale(); 233 234 icu::DateFormat* timeFormatter 235 = icu::DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale); 236 if (timeFormatter == NULL) 237 return NULL; 238 239 SimpleDateFormat* timeFormatterImpl 240 = static_cast<SimpleDateFormat*>(timeFormatter); 241 242 BString format; 243 fConventions.GetTimeFormat(style, format); 244 245 UnicodeString pattern(format.String()); 246 timeFormatterImpl->applyPattern(pattern); 247 248 return timeFormatter; 249 } 250