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
973de5837SJé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
271bad1ff3SAdrien Destugues U_NAMESPACE_USE
281bad1ff3SAdrien Destugues
291bad1ff3SAdrien Destugues
BTimeFormat()305d5ec05bSAdrien Destugues BTimeFormat::BTimeFormat()
315d5ec05bSAdrien Destugues : BFormat()
3203b2550eSAdrien Destugues {
335d5ec05bSAdrien Destugues }
3403b2550eSAdrien Destugues
355d5ec05bSAdrien Destugues
BTimeFormat(const BLanguage & language,const BFormattingConventions & conventions)365d5ec05bSAdrien Destugues BTimeFormat::BTimeFormat(const BLanguage& language,
375d5ec05bSAdrien Destugues const BFormattingConventions& conventions)
385d5ec05bSAdrien Destugues : BFormat(language, conventions)
395d5ec05bSAdrien Destugues {
4003b2550eSAdrien Destugues }
4103b2550eSAdrien Destugues
4203b2550eSAdrien Destugues
BTimeFormat(const BTimeFormat & other)4338ac8defSOliver Tappe BTimeFormat::BTimeFormat(const BTimeFormat &other)
4403b2550eSAdrien Destugues : BFormat(other)
45b2c385c0SAdrien Destugues {
4638ac8defSOliver Tappe }
4733eead33SAdrien Destugues
4803b2550eSAdrien Destugues
~BTimeFormat()4938ac8defSOliver Tappe BTimeFormat::~BTimeFormat()
5038ac8defSOliver Tappe {
5138ac8defSOliver Tappe }
5233eead33SAdrien Destugues
5303b2550eSAdrien Destugues
5426b0a53dSAdrien Destugues void
SetTimeFormat(BTimeFormatStyle style,const BString & format)5526b0a53dSAdrien Destugues BTimeFormat::SetTimeFormat(BTimeFormatStyle style,
5626b0a53dSAdrien Destugues const BString& format)
5726b0a53dSAdrien Destugues {
5826b0a53dSAdrien Destugues fConventions.SetExplicitTimeFormat(style, format);
5926b0a53dSAdrien Destugues }
6026b0a53dSAdrien Destugues
6126b0a53dSAdrien Destugues
6203b2550eSAdrien Destugues // #pragma mark - Formatting
6303b2550eSAdrien Destugues
6403b2550eSAdrien Destugues
6503b2550eSAdrien Destugues ssize_t
Format(char * string,size_t maxSize,time_t time,BTimeFormatStyle style) const6603b2550eSAdrien Destugues BTimeFormat::Format(char* string, size_t maxSize, time_t time,
6703b2550eSAdrien Destugues BTimeFormatStyle style) const
6838ac8defSOliver Tappe {
6926b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
70*779ab335SX512 if (!timeFormatter.IsSet())
7103b2550eSAdrien Destugues return B_NO_MEMORY;
7203b2550eSAdrien Destugues
7303b2550eSAdrien Destugues UnicodeString icuString;
7403b2550eSAdrien Destugues timeFormatter->format((UDate)time * 1000, icuString);
7503b2550eSAdrien Destugues
7603b2550eSAdrien Destugues CheckedArrayByteSink stringConverter(string, maxSize);
7703b2550eSAdrien Destugues icuString.toUTF8(stringConverter);
7803b2550eSAdrien Destugues
7903b2550eSAdrien Destugues if (stringConverter.Overflowed())
8003b2550eSAdrien Destugues return B_BAD_VALUE;
8103b2550eSAdrien Destugues
8203b2550eSAdrien Destugues return stringConverter.NumberOfBytesWritten();
8303b2550eSAdrien Destugues }
8403b2550eSAdrien Destugues
8503b2550eSAdrien Destugues
8603b2550eSAdrien Destugues status_t
Format(BString & string,const time_t time,const BTimeFormatStyle style,const BTimeZone * timeZone) const8703b2550eSAdrien Destugues BTimeFormat::Format(BString& string, const time_t time,
8803b2550eSAdrien Destugues const BTimeFormatStyle style, const BTimeZone* timeZone) const
8903b2550eSAdrien Destugues {
9026b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
91*779ab335SX512 if (!timeFormatter.IsSet())
9203b2550eSAdrien Destugues return B_NO_MEMORY;
9303b2550eSAdrien Destugues
9403b2550eSAdrien Destugues if (timeZone != NULL) {
9503b2550eSAdrien Destugues ObjectDeleter<TimeZone> icuTimeZone(
9603b2550eSAdrien Destugues TimeZone::createTimeZone(timeZone->ID().String()));
97*779ab335SX512 if (!icuTimeZone.IsSet())
9803b2550eSAdrien Destugues return B_NO_MEMORY;
9903b2550eSAdrien Destugues timeFormatter->setTimeZone(*icuTimeZone.Get());
10003b2550eSAdrien Destugues }
10103b2550eSAdrien Destugues
10203b2550eSAdrien Destugues UnicodeString icuString;
10303b2550eSAdrien Destugues timeFormatter->format((UDate)time * 1000, icuString);
10403b2550eSAdrien Destugues
10503b2550eSAdrien Destugues string.Truncate(0);
10603b2550eSAdrien Destugues BStringByteSink stringConverter(&string);
10703b2550eSAdrien Destugues icuString.toUTF8(stringConverter);
10803b2550eSAdrien Destugues
10903b2550eSAdrien Destugues return B_OK;
11003b2550eSAdrien Destugues }
11103b2550eSAdrien Destugues
11203b2550eSAdrien Destugues
11303b2550eSAdrien Destugues status_t
Format(BString & string,int * & fieldPositions,int & fieldCount,time_t time,BTimeFormatStyle style) const11403b2550eSAdrien Destugues BTimeFormat::Format(BString& string, int*& fieldPositions, int& fieldCount,
11503b2550eSAdrien Destugues time_t time, BTimeFormatStyle style) const
11603b2550eSAdrien Destugues {
11726b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
118*779ab335SX512 if (!timeFormatter.IsSet())
11903b2550eSAdrien Destugues return B_NO_MEMORY;
12003b2550eSAdrien Destugues
12103b2550eSAdrien Destugues fieldPositions = NULL;
12203b2550eSAdrien Destugues UErrorCode error = U_ZERO_ERROR;
12303b2550eSAdrien Destugues icu::FieldPositionIterator positionIterator;
12403b2550eSAdrien Destugues UnicodeString icuString;
12503b2550eSAdrien Destugues timeFormatter->format((UDate)time * 1000, icuString, &positionIterator,
12603b2550eSAdrien Destugues error);
12703b2550eSAdrien Destugues
12803b2550eSAdrien Destugues if (error != U_ZERO_ERROR)
12903b2550eSAdrien Destugues return B_BAD_VALUE;
13003b2550eSAdrien Destugues
13103b2550eSAdrien Destugues icu::FieldPosition field;
13203b2550eSAdrien Destugues std::vector<int> fieldPosStorage;
13303b2550eSAdrien Destugues fieldCount = 0;
13403b2550eSAdrien Destugues while (positionIterator.next(field)) {
13503b2550eSAdrien Destugues fieldPosStorage.push_back(field.getBeginIndex());
13603b2550eSAdrien Destugues fieldPosStorage.push_back(field.getEndIndex());
13703b2550eSAdrien Destugues fieldCount += 2;
13803b2550eSAdrien Destugues }
13903b2550eSAdrien Destugues
14003b2550eSAdrien Destugues fieldPositions = (int*) malloc(fieldCount * sizeof(int));
14103b2550eSAdrien Destugues
14203b2550eSAdrien Destugues for (int i = 0 ; i < fieldCount ; i++ )
14303b2550eSAdrien Destugues fieldPositions[i] = fieldPosStorage[i];
14403b2550eSAdrien Destugues
14503b2550eSAdrien Destugues string.Truncate(0);
14603b2550eSAdrien Destugues BStringByteSink stringConverter(&string);
14703b2550eSAdrien Destugues icuString.toUTF8(stringConverter);
14803b2550eSAdrien Destugues
14903b2550eSAdrien Destugues return B_OK;
15003b2550eSAdrien Destugues }
15103b2550eSAdrien Destugues
15203b2550eSAdrien Destugues
15303b2550eSAdrien Destugues status_t
GetTimeFields(BDateElement * & fields,int & fieldCount,BTimeFormatStyle style) const15403b2550eSAdrien Destugues BTimeFormat::GetTimeFields(BDateElement*& fields, int& fieldCount,
15503b2550eSAdrien Destugues BTimeFormatStyle style) const
15603b2550eSAdrien Destugues {
15726b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
158*779ab335SX512 if (!timeFormatter.IsSet())
15903b2550eSAdrien Destugues return B_NO_MEMORY;
16003b2550eSAdrien Destugues
16103b2550eSAdrien Destugues fields = NULL;
16203b2550eSAdrien Destugues UErrorCode error = U_ZERO_ERROR;
16303b2550eSAdrien Destugues icu::FieldPositionIterator positionIterator;
16403b2550eSAdrien Destugues UnicodeString icuString;
16503b2550eSAdrien Destugues time_t now;
16603b2550eSAdrien Destugues timeFormatter->format((UDate)time(&now) * 1000, icuString,
16703b2550eSAdrien Destugues &positionIterator, error);
16803b2550eSAdrien Destugues
16903b2550eSAdrien Destugues if (error != U_ZERO_ERROR)
17003b2550eSAdrien Destugues return B_BAD_VALUE;
17103b2550eSAdrien Destugues
17203b2550eSAdrien Destugues icu::FieldPosition field;
17303b2550eSAdrien Destugues std::vector<int> fieldPosStorage;
17403b2550eSAdrien Destugues fieldCount = 0;
17503b2550eSAdrien Destugues while (positionIterator.next(field)) {
17603b2550eSAdrien Destugues fieldPosStorage.push_back(field.getField());
17703b2550eSAdrien Destugues fieldCount ++;
17803b2550eSAdrien Destugues }
17903b2550eSAdrien Destugues
18003b2550eSAdrien Destugues fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement));
18103b2550eSAdrien Destugues
18203b2550eSAdrien Destugues for (int i = 0 ; i < fieldCount ; i++ ) {
18303b2550eSAdrien Destugues switch (fieldPosStorage[i]) {
18403b2550eSAdrien Destugues case UDAT_HOUR_OF_DAY1_FIELD:
18503b2550eSAdrien Destugues case UDAT_HOUR_OF_DAY0_FIELD:
18603b2550eSAdrien Destugues case UDAT_HOUR1_FIELD:
18703b2550eSAdrien Destugues case UDAT_HOUR0_FIELD:
18803b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_HOUR;
18903b2550eSAdrien Destugues break;
19003b2550eSAdrien Destugues case UDAT_MINUTE_FIELD:
19103b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_MINUTE;
19203b2550eSAdrien Destugues break;
19303b2550eSAdrien Destugues case UDAT_SECOND_FIELD:
19403b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_SECOND;
19503b2550eSAdrien Destugues break;
19603b2550eSAdrien Destugues case UDAT_AM_PM_FIELD:
19703b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_AM_PM;
19803b2550eSAdrien Destugues break;
19903b2550eSAdrien Destugues default:
20003b2550eSAdrien Destugues fields[i] = B_DATE_ELEMENT_INVALID;
20103b2550eSAdrien Destugues break;
20203b2550eSAdrien Destugues }
20303b2550eSAdrien Destugues }
20403b2550eSAdrien Destugues
20503b2550eSAdrien Destugues return B_OK;
20603b2550eSAdrien Destugues }
20703b2550eSAdrien Destugues
20803b2550eSAdrien Destugues
20926b0a53dSAdrien Destugues status_t
Parse(BString source,BTimeFormatStyle style,BTime & output)21026b0a53dSAdrien Destugues BTimeFormat::Parse(BString source, BTimeFormatStyle style, BTime& output)
21126b0a53dSAdrien Destugues {
21226b0a53dSAdrien Destugues ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
213*779ab335SX512 if (!timeFormatter.IsSet())
21426b0a53dSAdrien Destugues return B_NO_MEMORY;
21526b0a53dSAdrien Destugues
21626b0a53dSAdrien Destugues // If no timezone is specified in the time string, assume GMT
21726b0a53dSAdrien Destugues timeFormatter->setTimeZone(*icu::TimeZone::getGMT());
21826b0a53dSAdrien Destugues
21926b0a53dSAdrien Destugues ParsePosition p(0);
22026b0a53dSAdrien Destugues UDate date = timeFormatter->parse(UnicodeString::fromUTF8(source.String()),
22126b0a53dSAdrien Destugues p);
22226b0a53dSAdrien Destugues
22326b0a53dSAdrien Destugues output.SetTime(0, 0, 0);
22426b0a53dSAdrien Destugues output.AddMilliseconds(date);
22526b0a53dSAdrien Destugues
22626b0a53dSAdrien Destugues return B_OK;
22726b0a53dSAdrien Destugues }
22826b0a53dSAdrien Destugues
22926b0a53dSAdrien Destugues
23003b2550eSAdrien Destugues DateFormat*
_CreateTimeFormatter(const BTimeFormatStyle style) const23126b0a53dSAdrien Destugues BTimeFormat::_CreateTimeFormatter(const BTimeFormatStyle style) const
23203b2550eSAdrien Destugues {
23303b2550eSAdrien Destugues Locale* icuLocale
23403b2550eSAdrien Destugues = fConventions.UseStringsFromPreferredLanguage()
23503b2550eSAdrien Destugues ? BLanguage::Private(&fLanguage).ICULocale()
23603b2550eSAdrien Destugues : BFormattingConventions::Private(&fConventions).ICULocale();
23703b2550eSAdrien Destugues
23803b2550eSAdrien Destugues icu::DateFormat* timeFormatter
23903b2550eSAdrien Destugues = icu::DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale);
24003b2550eSAdrien Destugues if (timeFormatter == NULL)
24103b2550eSAdrien Destugues return NULL;
24203b2550eSAdrien Destugues
24303b2550eSAdrien Destugues SimpleDateFormat* timeFormatterImpl
24403b2550eSAdrien Destugues = static_cast<SimpleDateFormat*>(timeFormatter);
24503b2550eSAdrien Destugues
24626b0a53dSAdrien Destugues BString format;
24726b0a53dSAdrien Destugues fConventions.GetTimeFormat(style, format);
24826b0a53dSAdrien Destugues
24903b2550eSAdrien Destugues UnicodeString pattern(format.String());
25003b2550eSAdrien Destugues timeFormatterImpl->applyPattern(pattern);
25103b2550eSAdrien Destugues
25203b2550eSAdrien Destugues return timeFormatter;
253b2c385c0SAdrien Destugues }
254