xref: /haiku/src/kits/locale/TimeFormat.cpp (revision 73de58376ac8f983ae64a643e01ec5bf047208d2)
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