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