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 9*73de5837SJérôme Duval #include <unicode/uversion.h> 10b2c385c0SAdrien Destugues #include <TimeFormat.h> 11b2c385c0SAdrien Destugues 1203b2550eSAdrien Destugues #include <AutoDeleter.h> 1303b2550eSAdrien Destugues #include <Autolock.h> 1426b0a53dSAdrien Destugues #include <DateTime.h> 1503b2550eSAdrien Destugues #include <FormattingConventionsPrivate.h> 1603b2550eSAdrien Destugues #include <LanguagePrivate.h> 1703b2550eSAdrien Destugues #include <TimeZone.h> 18b2c385c0SAdrien Destugues 1903b2550eSAdrien Destugues #include <ICUWrapper.h> 2003b2550eSAdrien Destugues 2103b2550eSAdrien Destugues #include <unicode/datefmt.h> 2203b2550eSAdrien Destugues #include <unicode/smpdtfmt.h> 2303b2550eSAdrien Destugues 2403b2550eSAdrien Destugues #include <vector> 2503b2550eSAdrien Destugues 2603b2550eSAdrien Destugues 275d5ec05bSAdrien Destugues BTimeFormat::BTimeFormat() 285d5ec05bSAdrien Destugues : BFormat() 2903b2550eSAdrien Destugues { 305d5ec05bSAdrien Destugues } 3103b2550eSAdrien Destugues 325d5ec05bSAdrien Destugues 335d5ec05bSAdrien Destugues BTimeFormat::BTimeFormat(const BLanguage& language, 345d5ec05bSAdrien Destugues const BFormattingConventions& conventions) 355d5ec05bSAdrien Destugues : BFormat(language, conventions) 365d5ec05bSAdrien Destugues { 3703b2550eSAdrien Destugues } 3803b2550eSAdrien Destugues 3903b2550eSAdrien Destugues 4038ac8defSOliver Tappe BTimeFormat::BTimeFormat(const BTimeFormat &other) 4103b2550eSAdrien Destugues : BFormat(other) 42b2c385c0SAdrien Destugues { 4338ac8defSOliver Tappe } 4433eead33SAdrien Destugues 4503b2550eSAdrien Destugues 4638ac8defSOliver Tappe BTimeFormat::~BTimeFormat() 4738ac8defSOliver Tappe { 4838ac8defSOliver Tappe } 4933eead33SAdrien Destugues 5003b2550eSAdrien Destugues 5126b0a53dSAdrien Destugues void 5226b0a53dSAdrien Destugues BTimeFormat::SetTimeFormat(BTimeFormatStyle style, 5326b0a53dSAdrien Destugues const BString& format) 5426b0a53dSAdrien Destugues { 5526b0a53dSAdrien Destugues fConventions.SetExplicitTimeFormat(style, format); 5626b0a53dSAdrien Destugues } 5726b0a53dSAdrien Destugues 5826b0a53dSAdrien Destugues 5903b2550eSAdrien Destugues // #pragma mark - Formatting 6003b2550eSAdrien Destugues 6103b2550eSAdrien Destugues 6203b2550eSAdrien Destugues ssize_t 6303b2550eSAdrien Destugues BTimeFormat::Format(char* string, size_t maxSize, time_t time, 6403b2550eSAdrien Destugues BTimeFormatStyle style) const 6538ac8defSOliver Tappe { 6626b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 6703b2550eSAdrien Destugues if (timeFormatter.Get() == NULL) 6803b2550eSAdrien Destugues return B_NO_MEMORY; 6903b2550eSAdrien Destugues 7003b2550eSAdrien Destugues UnicodeString icuString; 7103b2550eSAdrien Destugues timeFormatter->format((UDate)time * 1000, icuString); 7203b2550eSAdrien Destugues 7303b2550eSAdrien Destugues CheckedArrayByteSink stringConverter(string, maxSize); 7403b2550eSAdrien Destugues icuString.toUTF8(stringConverter); 7503b2550eSAdrien Destugues 7603b2550eSAdrien Destugues if (stringConverter.Overflowed()) 7703b2550eSAdrien Destugues return B_BAD_VALUE; 7803b2550eSAdrien Destugues 7903b2550eSAdrien Destugues return stringConverter.NumberOfBytesWritten(); 8003b2550eSAdrien Destugues } 8103b2550eSAdrien Destugues 8203b2550eSAdrien Destugues 8303b2550eSAdrien Destugues status_t 8403b2550eSAdrien Destugues BTimeFormat::Format(BString& string, const time_t time, 8503b2550eSAdrien Destugues const BTimeFormatStyle style, const BTimeZone* timeZone) const 8603b2550eSAdrien Destugues { 8726b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 8803b2550eSAdrien Destugues if (timeFormatter.Get() == NULL) 8903b2550eSAdrien Destugues return B_NO_MEMORY; 9003b2550eSAdrien Destugues 9103b2550eSAdrien Destugues if (timeZone != NULL) { 9203b2550eSAdrien Destugues ObjectDeleter<TimeZone> icuTimeZone( 9303b2550eSAdrien Destugues TimeZone::createTimeZone(timeZone->ID().String())); 9403b2550eSAdrien Destugues if (icuTimeZone.Get() == NULL) 9503b2550eSAdrien Destugues return B_NO_MEMORY; 9603b2550eSAdrien Destugues timeFormatter->setTimeZone(*icuTimeZone.Get()); 9703b2550eSAdrien Destugues } 9803b2550eSAdrien Destugues 9903b2550eSAdrien Destugues UnicodeString icuString; 10003b2550eSAdrien Destugues timeFormatter->format((UDate)time * 1000, icuString); 10103b2550eSAdrien Destugues 10203b2550eSAdrien Destugues string.Truncate(0); 10303b2550eSAdrien Destugues BStringByteSink stringConverter(&string); 10403b2550eSAdrien Destugues icuString.toUTF8(stringConverter); 10503b2550eSAdrien Destugues 10603b2550eSAdrien Destugues return B_OK; 10703b2550eSAdrien Destugues } 10803b2550eSAdrien Destugues 10903b2550eSAdrien Destugues 11003b2550eSAdrien Destugues status_t 11103b2550eSAdrien Destugues BTimeFormat::Format(BString& string, int*& fieldPositions, int& fieldCount, 11203b2550eSAdrien Destugues time_t time, BTimeFormatStyle style) const 11303b2550eSAdrien Destugues { 11426b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 11503b2550eSAdrien Destugues if (timeFormatter.Get() == NULL) 11603b2550eSAdrien Destugues return B_NO_MEMORY; 11703b2550eSAdrien Destugues 11803b2550eSAdrien Destugues fieldPositions = NULL; 11903b2550eSAdrien Destugues UErrorCode error = U_ZERO_ERROR; 12003b2550eSAdrien Destugues icu::FieldPositionIterator positionIterator; 12103b2550eSAdrien Destugues UnicodeString icuString; 12203b2550eSAdrien Destugues timeFormatter->format((UDate)time * 1000, icuString, &positionIterator, 12303b2550eSAdrien Destugues error); 12403b2550eSAdrien Destugues 12503b2550eSAdrien Destugues if (error != U_ZERO_ERROR) 12603b2550eSAdrien Destugues return B_BAD_VALUE; 12703b2550eSAdrien Destugues 12803b2550eSAdrien Destugues icu::FieldPosition field; 12903b2550eSAdrien Destugues std::vector<int> fieldPosStorage; 13003b2550eSAdrien Destugues fieldCount = 0; 13103b2550eSAdrien Destugues while (positionIterator.next(field)) { 13203b2550eSAdrien Destugues fieldPosStorage.push_back(field.getBeginIndex()); 13303b2550eSAdrien Destugues fieldPosStorage.push_back(field.getEndIndex()); 13403b2550eSAdrien Destugues fieldCount += 2; 13503b2550eSAdrien Destugues } 13603b2550eSAdrien Destugues 13703b2550eSAdrien Destugues fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 13803b2550eSAdrien Destugues 13903b2550eSAdrien Destugues for (int i = 0 ; i < fieldCount ; i++ ) 14003b2550eSAdrien Destugues fieldPositions[i] = fieldPosStorage[i]; 14103b2550eSAdrien Destugues 14203b2550eSAdrien Destugues string.Truncate(0); 14303b2550eSAdrien Destugues BStringByteSink stringConverter(&string); 14403b2550eSAdrien Destugues icuString.toUTF8(stringConverter); 14503b2550eSAdrien Destugues 14603b2550eSAdrien Destugues return B_OK; 14703b2550eSAdrien Destugues } 14803b2550eSAdrien Destugues 14903b2550eSAdrien Destugues 15003b2550eSAdrien Destugues status_t 15103b2550eSAdrien Destugues BTimeFormat::GetTimeFields(BDateElement*& fields, int& fieldCount, 15203b2550eSAdrien Destugues BTimeFormatStyle style) const 15303b2550eSAdrien Destugues { 15426b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 15503b2550eSAdrien Destugues if (timeFormatter.Get() == NULL) 15603b2550eSAdrien Destugues return B_NO_MEMORY; 15703b2550eSAdrien Destugues 15803b2550eSAdrien Destugues fields = NULL; 15903b2550eSAdrien Destugues UErrorCode error = U_ZERO_ERROR; 16003b2550eSAdrien Destugues icu::FieldPositionIterator positionIterator; 16103b2550eSAdrien Destugues UnicodeString icuString; 16203b2550eSAdrien Destugues time_t now; 16303b2550eSAdrien Destugues timeFormatter->format((UDate)time(&now) * 1000, icuString, 16403b2550eSAdrien Destugues &positionIterator, error); 16503b2550eSAdrien Destugues 16603b2550eSAdrien Destugues if (error != U_ZERO_ERROR) 16703b2550eSAdrien Destugues return B_BAD_VALUE; 16803b2550eSAdrien Destugues 16903b2550eSAdrien Destugues icu::FieldPosition field; 17003b2550eSAdrien Destugues std::vector<int> fieldPosStorage; 17103b2550eSAdrien Destugues fieldCount = 0; 17203b2550eSAdrien Destugues while (positionIterator.next(field)) { 17303b2550eSAdrien Destugues fieldPosStorage.push_back(field.getField()); 17403b2550eSAdrien Destugues fieldCount ++; 17503b2550eSAdrien Destugues } 17603b2550eSAdrien Destugues 17703b2550eSAdrien Destugues fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 17803b2550eSAdrien Destugues 17903b2550eSAdrien Destugues for (int i = 0 ; i < fieldCount ; i++ ) { 18003b2550eSAdrien Destugues switch (fieldPosStorage[i]) { 18103b2550eSAdrien Destugues case UDAT_HOUR_OF_DAY1_FIELD: 18203b2550eSAdrien Destugues case UDAT_HOUR_OF_DAY0_FIELD: 18303b2550eSAdrien Destugues case UDAT_HOUR1_FIELD: 18403b2550eSAdrien Destugues case UDAT_HOUR0_FIELD: 18503b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_HOUR; 18603b2550eSAdrien Destugues break; 18703b2550eSAdrien Destugues case UDAT_MINUTE_FIELD: 18803b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_MINUTE; 18903b2550eSAdrien Destugues break; 19003b2550eSAdrien Destugues case UDAT_SECOND_FIELD: 19103b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_SECOND; 19203b2550eSAdrien Destugues break; 19303b2550eSAdrien Destugues case UDAT_AM_PM_FIELD: 19403b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_AM_PM; 19503b2550eSAdrien Destugues break; 19603b2550eSAdrien Destugues default: 19703b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_INVALID; 19803b2550eSAdrien Destugues break; 19903b2550eSAdrien Destugues } 20003b2550eSAdrien Destugues } 20103b2550eSAdrien Destugues 20203b2550eSAdrien Destugues return B_OK; 20303b2550eSAdrien Destugues } 20403b2550eSAdrien Destugues 20503b2550eSAdrien Destugues 20626b0a53dSAdrien Destugues status_t 20726b0a53dSAdrien Destugues BTimeFormat::Parse(BString source, BTimeFormatStyle style, BTime& output) 20826b0a53dSAdrien Destugues { 20926b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 21026b0a53dSAdrien Destugues if (timeFormatter.Get() == NULL) 21126b0a53dSAdrien Destugues return B_NO_MEMORY; 21226b0a53dSAdrien Destugues 21326b0a53dSAdrien Destugues // If no timezone is specified in the time string, assume GMT 21426b0a53dSAdrien Destugues timeFormatter->setTimeZone(*icu::TimeZone::getGMT()); 21526b0a53dSAdrien Destugues 21626b0a53dSAdrien Destugues ParsePosition p(0); 21726b0a53dSAdrien Destugues UDate date = timeFormatter->parse(UnicodeString::fromUTF8(source.String()), 21826b0a53dSAdrien Destugues p); 21926b0a53dSAdrien Destugues 22026b0a53dSAdrien Destugues output.SetTime(0, 0, 0); 22126b0a53dSAdrien Destugues output.AddMilliseconds(date); 22226b0a53dSAdrien Destugues 22326b0a53dSAdrien Destugues return B_OK; 22426b0a53dSAdrien Destugues } 22526b0a53dSAdrien Destugues 22626b0a53dSAdrien Destugues 22703b2550eSAdrien Destugues DateFormat* 22826b0a53dSAdrien Destugues BTimeFormat::_CreateTimeFormatter(const BTimeFormatStyle style) const 22903b2550eSAdrien Destugues { 23003b2550eSAdrien Destugues Locale* icuLocale 23103b2550eSAdrien Destugues = fConventions.UseStringsFromPreferredLanguage() 23203b2550eSAdrien Destugues ? BLanguage::Private(&fLanguage).ICULocale() 23303b2550eSAdrien Destugues : BFormattingConventions::Private(&fConventions).ICULocale(); 23403b2550eSAdrien Destugues 23503b2550eSAdrien Destugues icu::DateFormat* timeFormatter 23603b2550eSAdrien Destugues = icu::DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale); 23703b2550eSAdrien Destugues if (timeFormatter == NULL) 23803b2550eSAdrien Destugues return NULL; 23903b2550eSAdrien Destugues 24003b2550eSAdrien Destugues SimpleDateFormat* timeFormatterImpl 24103b2550eSAdrien Destugues = static_cast<SimpleDateFormat*>(timeFormatter); 24203b2550eSAdrien Destugues 24326b0a53dSAdrien Destugues BString format; 24426b0a53dSAdrien Destugues fConventions.GetTimeFormat(style, format); 24526b0a53dSAdrien Destugues 24603b2550eSAdrien Destugues UnicodeString pattern(format.String()); 24703b2550eSAdrien Destugues timeFormatterImpl->applyPattern(pattern); 24803b2550eSAdrien Destugues 24903b2550eSAdrien Destugues return timeFormatter; 250b2c385c0SAdrien Destugues } 251