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