xref: /haiku/src/kits/locale/DateTimeFormat.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
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  */
8 
9 #include <unicode/uversion.h>
10 #include <DateTimeFormat.h>
11 
12 #include <AutoDeleter.h>
13 #include <Autolock.h>
14 #include <FormattingConventionsPrivate.h>
15 #include <LanguagePrivate.h>
16 #include <TimeZone.h>
17 
18 #include <ICUWrapper.h>
19 
20 #include <unicode/datefmt.h>
21 #include <unicode/dtptngen.h>
22 #include <unicode/smpdtfmt.h>
23 
24 
25 BDateTimeFormat::BDateTimeFormat(const BLocale* locale)
26 	: BFormat(locale)
27 {
28 }
29 
30 
31 BDateTimeFormat::BDateTimeFormat(const BLanguage& language,
32 	const BFormattingConventions& conventions)
33 	: BFormat(language, conventions)
34 {
35 }
36 
37 
38 BDateTimeFormat::BDateTimeFormat(const BDateTimeFormat &other)
39 	: BFormat(other)
40 {
41 }
42 
43 
44 BDateTimeFormat::~BDateTimeFormat()
45 {
46 }
47 
48 
49 void
50 BDateTimeFormat::SetDateTimeFormat(BDateFormatStyle dateStyle,
51 	BTimeFormatStyle timeStyle, int32 elements) {
52 	UErrorCode error = U_ZERO_ERROR;
53 	DateTimePatternGenerator* generator
54 		= DateTimePatternGenerator::createInstance(
55 			*BLanguage::Private(&fLanguage).ICULocale(), error);
56 
57 	BString skeleton;
58 	if (elements & B_DATE_ELEMENT_YEAR)
59 		skeleton << "yyyy";
60 	if (elements & B_DATE_ELEMENT_MONTH)
61 		skeleton << "MM";
62 	if (elements & B_DATE_ELEMENT_WEEKDAY)
63 		skeleton << "eee";
64 	if (elements & B_DATE_ELEMENT_DAY)
65 		skeleton << "dd";
66 	if (elements & B_DATE_ELEMENT_AM_PM)
67 		skeleton << "a";
68 	if (elements & B_DATE_ELEMENT_HOUR) {
69 		if (fConventions.Use24HourClock())
70 			skeleton << "k";
71 		else
72 			skeleton << "K";
73 	}
74 	if (elements & B_DATE_ELEMENT_MINUTE)
75 		skeleton << "mm";
76 	if (elements & B_DATE_ELEMENT_SECOND)
77 		skeleton << "ss";
78 	if (elements & B_DATE_ELEMENT_TIMEZONE)
79 		skeleton << "z";
80 
81 	UnicodeString pattern = generator->getBestPattern(
82 		UnicodeString::fromUTF8(skeleton.String()), error);
83 
84 	BString buffer;
85 	BStringByteSink stringConverter(&buffer);
86 	pattern.toUTF8(stringConverter);
87 
88 	fConventions.SetExplicitDateTimeFormat(dateStyle, timeStyle, buffer);
89 
90 	delete generator;
91 }
92 
93 
94 // #pragma mark - Formatting
95 
96 
97 ssize_t
98 BDateTimeFormat::Format(char* target, size_t maxSize, time_t time,
99 	BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle) const
100 {
101 	BString format;
102 	fConventions.GetDateTimeFormat(dateStyle, timeStyle, format);
103 	ObjectDeleter<DateFormat> dateFormatter(_CreateDateTimeFormatter(format));
104 	if (dateFormatter.Get() == NULL)
105 		return B_NO_MEMORY;
106 
107 	UnicodeString icuString;
108 	dateFormatter->format((UDate)time * 1000, icuString);
109 
110 	CheckedArrayByteSink stringConverter(target, maxSize);
111 	icuString.toUTF8(stringConverter);
112 
113 	if (stringConverter.Overflowed())
114 		return B_BAD_VALUE;
115 
116 	return stringConverter.NumberOfBytesWritten();
117 }
118 
119 
120 status_t
121 BDateTimeFormat::Format(BString& target, const time_t time,
122 	BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle,
123 	const BTimeZone* timeZone) const
124 {
125 	BString format;
126 	fConventions.GetDateTimeFormat(dateStyle, timeStyle, format);
127 	ObjectDeleter<DateFormat> dateFormatter(_CreateDateTimeFormatter(format));
128 	if (dateFormatter.Get() == NULL)
129 		return B_NO_MEMORY;
130 
131 	if (timeZone != NULL) {
132 		ObjectDeleter<TimeZone> icuTimeZone(
133 			TimeZone::createTimeZone(timeZone->ID().String()));
134 		if (icuTimeZone.Get() == NULL)
135 			return B_NO_MEMORY;
136 		dateFormatter->setTimeZone(*icuTimeZone.Get());
137 	}
138 
139 	UnicodeString icuString;
140 	dateFormatter->format((UDate)time * 1000, icuString);
141 
142 	target.Truncate(0);
143 	BStringByteSink stringConverter(&target);
144 	icuString.toUTF8(stringConverter);
145 
146 	return B_OK;
147 }
148 
149 
150 DateFormat*
151 BDateTimeFormat::_CreateDateTimeFormatter(const BString& format) const
152 {
153 	Locale* icuLocale
154 		= fConventions.UseStringsFromPreferredLanguage()
155 			? BLanguage::Private(&fLanguage).ICULocale()
156 			: BFormattingConventions::Private(&fConventions).ICULocale();
157 
158 	icu::DateFormat* dateFormatter = icu::DateFormat::createDateTimeInstance(
159 		DateFormat::kDefault, DateFormat::kDefault, *icuLocale);
160 	if (dateFormatter == NULL)
161 		return NULL;
162 
163 	SimpleDateFormat* dateFormatterImpl
164 		= static_cast<SimpleDateFormat*>(dateFormatter);
165 
166 	UnicodeString pattern(format.String());
167 	dateFormatterImpl->applyPattern(pattern);
168 
169 	return dateFormatter;
170 }
171