1b2c385c0SAdrien Destugues /* 203b2550eSAdrien Destugues * Copyright 2010-2014, Haiku, Inc. All Rights Reserved. 3b2c385c0SAdrien Destugues * Distributed under the terms of the MIT License. 438ac8defSOliver Tappe * 538ac8defSOliver Tappe * Authors: 638ac8defSOliver Tappe * Oliver Tappe <zooey@hirschkaefer.de> 7b2c385c0SAdrien Destugues */ 8b2c385c0SAdrien Destugues 9b2c385c0SAdrien Destugues #include <TimeFormat.h> 10b2c385c0SAdrien Destugues 1103b2550eSAdrien Destugues #include <AutoDeleter.h> 1203b2550eSAdrien Destugues #include <Autolock.h> 13*26b0a53dSAdrien Destugues #include <DateTime.h> 1403b2550eSAdrien Destugues #include <FormattingConventionsPrivate.h> 1503b2550eSAdrien Destugues #include <LanguagePrivate.h> 1603b2550eSAdrien Destugues #include <TimeZone.h> 17b2c385c0SAdrien Destugues 1803b2550eSAdrien Destugues #include <ICUWrapper.h> 1903b2550eSAdrien Destugues 2003b2550eSAdrien Destugues #include <unicode/datefmt.h> 2103b2550eSAdrien Destugues #include <unicode/smpdtfmt.h> 2203b2550eSAdrien Destugues 2303b2550eSAdrien Destugues #include <vector> 2403b2550eSAdrien Destugues 2503b2550eSAdrien Destugues 2603b2550eSAdrien Destugues BTimeFormat::BTimeFormat(const BLanguage* const language, 2703b2550eSAdrien Destugues const BFormattingConventions* const conventions) 2803b2550eSAdrien Destugues { 2903b2550eSAdrien Destugues if (conventions != NULL) 3003b2550eSAdrien Destugues fConventions = *conventions; 3103b2550eSAdrien Destugues 3203b2550eSAdrien Destugues if (language != NULL) 3303b2550eSAdrien Destugues fLanguage = *language; 3403b2550eSAdrien Destugues } 3503b2550eSAdrien Destugues 3603b2550eSAdrien Destugues 3738ac8defSOliver Tappe BTimeFormat::BTimeFormat(const BTimeFormat &other) 3803b2550eSAdrien Destugues : BFormat(other) 39b2c385c0SAdrien Destugues { 4038ac8defSOliver Tappe } 4133eead33SAdrien Destugues 4203b2550eSAdrien Destugues 4338ac8defSOliver Tappe BTimeFormat::~BTimeFormat() 4438ac8defSOliver Tappe { 4538ac8defSOliver Tappe } 4633eead33SAdrien Destugues 4703b2550eSAdrien Destugues 48*26b0a53dSAdrien Destugues void 49*26b0a53dSAdrien Destugues BTimeFormat::SetTimeFormat(BTimeFormatStyle style, 50*26b0a53dSAdrien Destugues const BString& format) 51*26b0a53dSAdrien Destugues { 52*26b0a53dSAdrien Destugues fConventions.SetExplicitTimeFormat(style, format); 53*26b0a53dSAdrien Destugues } 54*26b0a53dSAdrien Destugues 55*26b0a53dSAdrien Destugues 5603b2550eSAdrien Destugues // #pragma mark - Formatting 5703b2550eSAdrien Destugues 5803b2550eSAdrien Destugues 5903b2550eSAdrien Destugues ssize_t 6003b2550eSAdrien Destugues BTimeFormat::Format(char* string, size_t maxSize, time_t time, 6103b2550eSAdrien Destugues BTimeFormatStyle style) const 6238ac8defSOliver Tappe { 6303b2550eSAdrien Destugues BAutolock lock(fLock); 6403b2550eSAdrien Destugues if (!lock.IsLocked()) 65b2c385c0SAdrien Destugues return B_ERROR; 6603b2550eSAdrien Destugues 67*26b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 6803b2550eSAdrien Destugues if (timeFormatter.Get() == NULL) 6903b2550eSAdrien Destugues return B_NO_MEMORY; 7003b2550eSAdrien Destugues 7103b2550eSAdrien Destugues UnicodeString icuString; 7203b2550eSAdrien Destugues timeFormatter->format((UDate)time * 1000, icuString); 7303b2550eSAdrien Destugues 7403b2550eSAdrien Destugues CheckedArrayByteSink stringConverter(string, maxSize); 7503b2550eSAdrien Destugues icuString.toUTF8(stringConverter); 7603b2550eSAdrien Destugues 7703b2550eSAdrien Destugues if (stringConverter.Overflowed()) 7803b2550eSAdrien Destugues return B_BAD_VALUE; 7903b2550eSAdrien Destugues 8003b2550eSAdrien Destugues return stringConverter.NumberOfBytesWritten(); 8103b2550eSAdrien Destugues } 8203b2550eSAdrien Destugues 8303b2550eSAdrien Destugues 8403b2550eSAdrien Destugues status_t 8503b2550eSAdrien Destugues BTimeFormat::Format(BString& string, const time_t time, 8603b2550eSAdrien Destugues const BTimeFormatStyle style, const BTimeZone* timeZone) const 8703b2550eSAdrien Destugues { 8803b2550eSAdrien Destugues BAutolock lock(fLock); 8903b2550eSAdrien Destugues if (!lock.IsLocked()) 9003b2550eSAdrien Destugues return B_ERROR; 9103b2550eSAdrien Destugues 92*26b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 9303b2550eSAdrien Destugues if (timeFormatter.Get() == NULL) 9403b2550eSAdrien Destugues return B_NO_MEMORY; 9503b2550eSAdrien Destugues 9603b2550eSAdrien Destugues if (timeZone != NULL) { 9703b2550eSAdrien Destugues ObjectDeleter<TimeZone> icuTimeZone( 9803b2550eSAdrien Destugues TimeZone::createTimeZone(timeZone->ID().String())); 9903b2550eSAdrien Destugues if (icuTimeZone.Get() == NULL) 10003b2550eSAdrien Destugues return B_NO_MEMORY; 10103b2550eSAdrien Destugues timeFormatter->setTimeZone(*icuTimeZone.Get()); 10203b2550eSAdrien Destugues } 10303b2550eSAdrien Destugues 10403b2550eSAdrien Destugues UnicodeString icuString; 10503b2550eSAdrien Destugues timeFormatter->format((UDate)time * 1000, icuString); 10603b2550eSAdrien Destugues 10703b2550eSAdrien Destugues string.Truncate(0); 10803b2550eSAdrien Destugues BStringByteSink stringConverter(&string); 10903b2550eSAdrien Destugues icuString.toUTF8(stringConverter); 11003b2550eSAdrien Destugues 11103b2550eSAdrien Destugues return B_OK; 11203b2550eSAdrien Destugues } 11303b2550eSAdrien Destugues 11403b2550eSAdrien Destugues 11503b2550eSAdrien Destugues status_t 11603b2550eSAdrien Destugues BTimeFormat::Format(BString& string, int*& fieldPositions, int& fieldCount, 11703b2550eSAdrien Destugues time_t time, BTimeFormatStyle style) const 11803b2550eSAdrien Destugues { 11903b2550eSAdrien Destugues BAutolock lock(fLock); 12003b2550eSAdrien Destugues if (!lock.IsLocked()) 12103b2550eSAdrien Destugues return B_ERROR; 12203b2550eSAdrien Destugues 123*26b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 12403b2550eSAdrien Destugues if (timeFormatter.Get() == NULL) 12503b2550eSAdrien Destugues return B_NO_MEMORY; 12603b2550eSAdrien Destugues 12703b2550eSAdrien Destugues fieldPositions = NULL; 12803b2550eSAdrien Destugues UErrorCode error = U_ZERO_ERROR; 12903b2550eSAdrien Destugues icu::FieldPositionIterator positionIterator; 13003b2550eSAdrien Destugues UnicodeString icuString; 13103b2550eSAdrien Destugues timeFormatter->format((UDate)time * 1000, icuString, &positionIterator, 13203b2550eSAdrien Destugues error); 13303b2550eSAdrien Destugues 13403b2550eSAdrien Destugues if (error != U_ZERO_ERROR) 13503b2550eSAdrien Destugues return B_BAD_VALUE; 13603b2550eSAdrien Destugues 13703b2550eSAdrien Destugues icu::FieldPosition field; 13803b2550eSAdrien Destugues std::vector<int> fieldPosStorage; 13903b2550eSAdrien Destugues fieldCount = 0; 14003b2550eSAdrien Destugues while (positionIterator.next(field)) { 14103b2550eSAdrien Destugues fieldPosStorage.push_back(field.getBeginIndex()); 14203b2550eSAdrien Destugues fieldPosStorage.push_back(field.getEndIndex()); 14303b2550eSAdrien Destugues fieldCount += 2; 14403b2550eSAdrien Destugues } 14503b2550eSAdrien Destugues 14603b2550eSAdrien Destugues fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 14703b2550eSAdrien Destugues 14803b2550eSAdrien Destugues for (int i = 0 ; i < fieldCount ; i++ ) 14903b2550eSAdrien Destugues fieldPositions[i] = fieldPosStorage[i]; 15003b2550eSAdrien Destugues 15103b2550eSAdrien Destugues string.Truncate(0); 15203b2550eSAdrien Destugues BStringByteSink stringConverter(&string); 15303b2550eSAdrien Destugues icuString.toUTF8(stringConverter); 15403b2550eSAdrien Destugues 15503b2550eSAdrien Destugues return B_OK; 15603b2550eSAdrien Destugues } 15703b2550eSAdrien Destugues 15803b2550eSAdrien Destugues 15903b2550eSAdrien Destugues status_t 16003b2550eSAdrien Destugues BTimeFormat::GetTimeFields(BDateElement*& fields, int& fieldCount, 16103b2550eSAdrien Destugues BTimeFormatStyle style) const 16203b2550eSAdrien Destugues { 16303b2550eSAdrien Destugues BAutolock lock(fLock); 16403b2550eSAdrien Destugues if (!lock.IsLocked()) 16503b2550eSAdrien Destugues return B_ERROR; 16603b2550eSAdrien Destugues 167*26b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 16803b2550eSAdrien Destugues if (timeFormatter.Get() == NULL) 16903b2550eSAdrien Destugues return B_NO_MEMORY; 17003b2550eSAdrien Destugues 17103b2550eSAdrien Destugues fields = NULL; 17203b2550eSAdrien Destugues UErrorCode error = U_ZERO_ERROR; 17303b2550eSAdrien Destugues icu::FieldPositionIterator positionIterator; 17403b2550eSAdrien Destugues UnicodeString icuString; 17503b2550eSAdrien Destugues time_t now; 17603b2550eSAdrien Destugues timeFormatter->format((UDate)time(&now) * 1000, icuString, 17703b2550eSAdrien Destugues &positionIterator, error); 17803b2550eSAdrien Destugues 17903b2550eSAdrien Destugues if (error != U_ZERO_ERROR) 18003b2550eSAdrien Destugues return B_BAD_VALUE; 18103b2550eSAdrien Destugues 18203b2550eSAdrien Destugues icu::FieldPosition field; 18303b2550eSAdrien Destugues std::vector<int> fieldPosStorage; 18403b2550eSAdrien Destugues fieldCount = 0; 18503b2550eSAdrien Destugues while (positionIterator.next(field)) { 18603b2550eSAdrien Destugues fieldPosStorage.push_back(field.getField()); 18703b2550eSAdrien Destugues fieldCount ++; 18803b2550eSAdrien Destugues } 18903b2550eSAdrien Destugues 19003b2550eSAdrien Destugues fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 19103b2550eSAdrien Destugues 19203b2550eSAdrien Destugues for (int i = 0 ; i < fieldCount ; i++ ) { 19303b2550eSAdrien Destugues switch (fieldPosStorage[i]) { 19403b2550eSAdrien Destugues case UDAT_HOUR_OF_DAY1_FIELD: 19503b2550eSAdrien Destugues case UDAT_HOUR_OF_DAY0_FIELD: 19603b2550eSAdrien Destugues case UDAT_HOUR1_FIELD: 19703b2550eSAdrien Destugues case UDAT_HOUR0_FIELD: 19803b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_HOUR; 19903b2550eSAdrien Destugues break; 20003b2550eSAdrien Destugues case UDAT_MINUTE_FIELD: 20103b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_MINUTE; 20203b2550eSAdrien Destugues break; 20303b2550eSAdrien Destugues case UDAT_SECOND_FIELD: 20403b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_SECOND; 20503b2550eSAdrien Destugues break; 20603b2550eSAdrien Destugues case UDAT_AM_PM_FIELD: 20703b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_AM_PM; 20803b2550eSAdrien Destugues break; 20903b2550eSAdrien Destugues default: 21003b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_INVALID; 21103b2550eSAdrien Destugues break; 21203b2550eSAdrien Destugues } 21303b2550eSAdrien Destugues } 21403b2550eSAdrien Destugues 21503b2550eSAdrien Destugues return B_OK; 21603b2550eSAdrien Destugues } 21703b2550eSAdrien Destugues 21803b2550eSAdrien Destugues 219*26b0a53dSAdrien Destugues status_t 220*26b0a53dSAdrien Destugues BTimeFormat::Parse(BString source, BTimeFormatStyle style, BTime& output) 221*26b0a53dSAdrien Destugues { 222*26b0a53dSAdrien Destugues BAutolock lock(fLock); 223*26b0a53dSAdrien Destugues if (!lock.IsLocked()) 224*26b0a53dSAdrien Destugues return B_ERROR; 225*26b0a53dSAdrien Destugues 226*26b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 227*26b0a53dSAdrien Destugues if (timeFormatter.Get() == NULL) 228*26b0a53dSAdrien Destugues return B_NO_MEMORY; 229*26b0a53dSAdrien Destugues 230*26b0a53dSAdrien Destugues // If no timezone is specified in the time string, assume GMT 231*26b0a53dSAdrien Destugues timeFormatter->setTimeZone(*icu::TimeZone::getGMT()); 232*26b0a53dSAdrien Destugues 233*26b0a53dSAdrien Destugues ParsePosition p(0); 234*26b0a53dSAdrien Destugues UDate date = timeFormatter->parse(UnicodeString::fromUTF8(source.String()), 235*26b0a53dSAdrien Destugues p); 236*26b0a53dSAdrien Destugues 237*26b0a53dSAdrien Destugues printf("T %f\n", date); 238*26b0a53dSAdrien Destugues 239*26b0a53dSAdrien Destugues output.SetTime(0, 0, 0); 240*26b0a53dSAdrien Destugues output.AddMilliseconds(date); 241*26b0a53dSAdrien Destugues 242*26b0a53dSAdrien Destugues return B_OK; 243*26b0a53dSAdrien Destugues } 244*26b0a53dSAdrien Destugues 245*26b0a53dSAdrien Destugues 24603b2550eSAdrien Destugues DateFormat* 247*26b0a53dSAdrien Destugues BTimeFormat::_CreateTimeFormatter(const BTimeFormatStyle style) const 24803b2550eSAdrien Destugues { 24903b2550eSAdrien Destugues Locale* icuLocale 25003b2550eSAdrien Destugues = fConventions.UseStringsFromPreferredLanguage() 25103b2550eSAdrien Destugues ? BLanguage::Private(&fLanguage).ICULocale() 25203b2550eSAdrien Destugues : BFormattingConventions::Private(&fConventions).ICULocale(); 25303b2550eSAdrien Destugues 25403b2550eSAdrien Destugues icu::DateFormat* timeFormatter 25503b2550eSAdrien Destugues = icu::DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale); 25603b2550eSAdrien Destugues if (timeFormatter == NULL) 25703b2550eSAdrien Destugues return NULL; 25803b2550eSAdrien Destugues 25903b2550eSAdrien Destugues SimpleDateFormat* timeFormatterImpl 26003b2550eSAdrien Destugues = static_cast<SimpleDateFormat*>(timeFormatter); 26103b2550eSAdrien Destugues 262*26b0a53dSAdrien Destugues BString format; 263*26b0a53dSAdrien Destugues fConventions.GetTimeFormat(style, format); 264*26b0a53dSAdrien Destugues 26503b2550eSAdrien Destugues UnicodeString pattern(format.String()); 26603b2550eSAdrien Destugues timeFormatterImpl->applyPattern(pattern); 26703b2550eSAdrien Destugues 26803b2550eSAdrien Destugues return timeFormatter; 269b2c385c0SAdrien Destugues } 270