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