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 * Adrien Desutugues <pulkomandy@pulkomandy.tk> 8 */ 9 10 #include <DateFormat.h> 11 12 #include <AutoDeleter.h> 13 #include <Autolock.h> 14 #include <FormattingConventionsPrivate.h> 15 #include <LanguagePrivate.h> 16 #include <Locale.h> 17 #include <LocaleRoster.h> 18 #include <TimeZone.h> 19 20 #include <ICUWrapper.h> 21 22 #include <unicode/datefmt.h> 23 #include <unicode/smpdtfmt.h> 24 25 #include <vector> 26 27 28 BDateFormat::BDateFormat(const BLanguage* const language, 29 const BFormattingConventions* const conventions) 30 { 31 if (conventions != NULL) 32 fConventions = *conventions; 33 34 if (language != NULL) 35 fLanguage = *language; 36 } 37 38 39 BDateFormat::BDateFormat(const BDateFormat &other) 40 : BFormat(other) 41 { 42 } 43 44 45 BDateFormat::~BDateFormat() 46 { 47 } 48 49 50 status_t 51 BDateFormat::GetDateFormat(BDateFormatStyle style, 52 BString& outFormat) const 53 { 54 return fConventions.GetDateFormat(style, outFormat); 55 } 56 57 58 void 59 BDateFormat::SetDateFormat(BDateFormatStyle style, 60 const BString& format) 61 { 62 fConventions.SetExplicitDateFormat(style, format); 63 } 64 65 66 ssize_t 67 BDateFormat::Format(char* string, const size_t maxSize, const time_t time, 68 const BDateFormatStyle style) const 69 { 70 BAutolock lock(fLock); 71 if (!lock.IsLocked()) 72 return B_ERROR; 73 74 BString format; 75 fConventions.GetDateFormat(style, format); 76 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 77 if (dateFormatter.Get() == NULL) 78 return B_NO_MEMORY; 79 80 UnicodeString icuString; 81 dateFormatter->format((UDate)time * 1000, icuString); 82 83 CheckedArrayByteSink stringConverter(string, maxSize); 84 icuString.toUTF8(stringConverter); 85 86 if (stringConverter.Overflowed()) 87 return B_BAD_VALUE; 88 89 return stringConverter.NumberOfBytesWritten(); 90 } 91 92 93 status_t 94 BDateFormat::Format(BString& string, const time_t time, 95 const BDateFormatStyle style, const BTimeZone* timeZone) const 96 { 97 BAutolock lock(fLock); 98 if (!lock.IsLocked()) 99 return B_ERROR; 100 101 BString format; 102 fConventions.GetDateFormat(style, format); 103 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 104 if (dateFormatter.Get() == NULL) 105 return B_NO_MEMORY; 106 107 if (timeZone != NULL) { 108 ObjectDeleter<TimeZone> icuTimeZone( 109 TimeZone::createTimeZone(timeZone->ID().String())); 110 if (icuTimeZone.Get() == NULL) 111 return B_NO_MEMORY; 112 dateFormatter->setTimeZone(*icuTimeZone.Get()); 113 } 114 115 UnicodeString icuString; 116 dateFormatter->format((UDate)time * 1000, icuString); 117 118 string.Truncate(0); 119 BStringByteSink stringConverter(&string); 120 icuString.toUTF8(stringConverter); 121 122 return B_OK; 123 } 124 125 126 status_t 127 BDateFormat::Format(BString& string, const BDate& time, 128 const BDateFormatStyle style, const BTimeZone* timeZone) const 129 { 130 if (!time.IsValid()) 131 return B_BAD_DATA; 132 133 BAutolock lock(fLock); 134 if (!lock.IsLocked()) 135 return B_ERROR; 136 137 BString format; 138 fConventions.GetDateFormat(style, format); 139 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 140 if (dateFormatter.Get() == NULL) 141 return B_NO_MEMORY; 142 143 UErrorCode err = U_ZERO_ERROR; 144 ObjectDeleter<Calendar> calendar(Calendar::createInstance(err)); 145 if (!U_SUCCESS(err)) 146 return B_NO_MEMORY; 147 148 if (timeZone != NULL) { 149 ObjectDeleter<TimeZone> icuTimeZone( 150 TimeZone::createTimeZone(timeZone->ID().String())); 151 if (icuTimeZone.Get() == NULL) 152 return B_NO_MEMORY; 153 dateFormatter->setTimeZone(*icuTimeZone.Get()); 154 calendar->setTimeZone(*icuTimeZone.Get()); 155 } 156 157 // Note ICU calendar uses months in range 0..11, while we use the more 158 // natural 1..12 in BDate. 159 calendar->set(time.Year(), time.Month() - 1, time.Day()); 160 161 UnicodeString icuString; 162 FieldPosition p; 163 dateFormatter->format(*calendar.Get(), icuString, p); 164 165 string.Truncate(0); 166 BStringByteSink stringConverter(&string); 167 icuString.toUTF8(stringConverter); 168 169 return B_OK; 170 } 171 172 173 status_t 174 BDateFormat::Format(BString& string, int*& fieldPositions, int& fieldCount, 175 const time_t time, const BDateFormatStyle style) const 176 { 177 BAutolock lock(fLock); 178 if (!lock.IsLocked()) 179 return B_ERROR; 180 181 BString format; 182 fConventions.GetDateFormat(style, format); 183 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 184 if (dateFormatter.Get() == NULL) 185 return B_NO_MEMORY; 186 187 fieldPositions = NULL; 188 UErrorCode error = U_ZERO_ERROR; 189 icu::FieldPositionIterator positionIterator; 190 UnicodeString icuString; 191 dateFormatter->format((UDate)time * 1000, icuString, &positionIterator, 192 error); 193 194 if (error != U_ZERO_ERROR) 195 return B_BAD_VALUE; 196 197 icu::FieldPosition field; 198 std::vector<int> fieldPosStorage; 199 fieldCount = 0; 200 while (positionIterator.next(field)) { 201 fieldPosStorage.push_back(field.getBeginIndex()); 202 fieldPosStorage.push_back(field.getEndIndex()); 203 fieldCount += 2; 204 } 205 206 fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 207 208 for (int i = 0 ; i < fieldCount ; i++ ) 209 fieldPositions[i] = fieldPosStorage[i]; 210 211 string.Truncate(0); 212 BStringByteSink stringConverter(&string); 213 214 icuString.toUTF8(stringConverter); 215 216 return B_OK; 217 } 218 219 220 status_t 221 BDateFormat::GetFields(BDateElement*& fields, int& fieldCount, 222 BDateFormatStyle style) const 223 { 224 BAutolock lock(fLock); 225 if (!lock.IsLocked()) 226 return B_ERROR; 227 228 BString format; 229 fConventions.GetDateFormat(style, format); 230 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 231 if (dateFormatter.Get() == NULL) 232 return B_NO_MEMORY; 233 234 fields = NULL; 235 UErrorCode error = U_ZERO_ERROR; 236 icu::FieldPositionIterator positionIterator; 237 UnicodeString icuString; 238 time_t now; 239 dateFormatter->format((UDate)time(&now) * 1000, icuString, 240 &positionIterator, error); 241 242 if (U_FAILURE(error)) 243 return B_BAD_VALUE; 244 245 icu::FieldPosition field; 246 std::vector<int> fieldPosStorage; 247 fieldCount = 0; 248 while (positionIterator.next(field)) { 249 fieldPosStorage.push_back(field.getField()); 250 fieldCount ++; 251 } 252 253 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 254 255 for (int i = 0 ; i < fieldCount ; i++ ) { 256 switch (fieldPosStorage[i]) { 257 case UDAT_YEAR_FIELD: 258 fields[i] = B_DATE_ELEMENT_YEAR; 259 break; 260 case UDAT_MONTH_FIELD: 261 fields[i] = B_DATE_ELEMENT_MONTH; 262 break; 263 case UDAT_DATE_FIELD: 264 fields[i] = B_DATE_ELEMENT_DAY; 265 break; 266 default: 267 fields[i] = B_DATE_ELEMENT_INVALID; 268 break; 269 } 270 } 271 272 return B_OK; 273 } 274 275 276 status_t 277 BDateFormat::GetStartOfWeek(BWeekday* startOfWeek) const 278 { 279 if (startOfWeek == NULL) 280 return B_BAD_VALUE; 281 282 BAutolock lock(fLock); 283 if (!lock.IsLocked()) 284 return B_ERROR; 285 286 UErrorCode err = U_ZERO_ERROR; 287 ObjectDeleter<Calendar> calendar = Calendar::createInstance( 288 *BFormattingConventions::Private(&fConventions).ICULocale(), err); 289 290 if (U_FAILURE(err)) 291 return B_ERROR; 292 293 UCalendarDaysOfWeek icuWeekStart = calendar->getFirstDayOfWeek(err); 294 if (U_FAILURE(err)) 295 return B_ERROR; 296 297 switch (icuWeekStart) { 298 case UCAL_SUNDAY: 299 *startOfWeek = B_WEEKDAY_SUNDAY; 300 break; 301 case UCAL_MONDAY: 302 *startOfWeek = B_WEEKDAY_MONDAY; 303 break; 304 case UCAL_TUESDAY: 305 *startOfWeek = B_WEEKDAY_TUESDAY; 306 break; 307 case UCAL_WEDNESDAY: 308 *startOfWeek = B_WEEKDAY_WEDNESDAY; 309 break; 310 case UCAL_THURSDAY: 311 *startOfWeek = B_WEEKDAY_THURSDAY; 312 break; 313 case UCAL_FRIDAY: 314 *startOfWeek = B_WEEKDAY_FRIDAY; 315 break; 316 case UCAL_SATURDAY: 317 *startOfWeek = B_WEEKDAY_SATURDAY; 318 break; 319 default: 320 return B_ERROR; 321 } 322 323 return B_OK; 324 } 325 326 327 DateFormat* 328 BDateFormat::_CreateDateFormatter(const BString& format) const 329 { 330 Locale* icuLocale 331 = fConventions.UseStringsFromPreferredLanguage() 332 ? BLanguage::Private(&fLanguage).ICULocale() 333 : BFormattingConventions::Private(&fConventions).ICULocale(); 334 335 icu::DateFormat* dateFormatter 336 = icu::DateFormat::createDateInstance(DateFormat::kShort, *icuLocale); 337 if (dateFormatter == NULL) 338 return NULL; 339 340 SimpleDateFormat* dateFormatterImpl 341 = static_cast<SimpleDateFormat*>(dateFormatter); 342 343 UnicodeString pattern(format.String()); 344 dateFormatterImpl->applyPattern(pattern); 345 346 return dateFormatter; 347 } 348 349 350