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 <TimeFormat.h>
11
12 #include <AutoDeleter.h>
13 #include <Autolock.h>
14 #include <DateTime.h>
15 #include <FormattingConventionsPrivate.h>
16 #include <LanguagePrivate.h>
17 #include <TimeZone.h>
18
19 #include <ICUWrapper.h>
20
21 #include <unicode/datefmt.h>
22 #include <unicode/smpdtfmt.h>
23
24 #include <vector>
25
26
27 U_NAMESPACE_USE
28
29
BTimeFormat()30 BTimeFormat::BTimeFormat()
31 : BFormat()
32 {
33 }
34
35
BTimeFormat(const BLanguage & language,const BFormattingConventions & conventions)36 BTimeFormat::BTimeFormat(const BLanguage& language,
37 const BFormattingConventions& conventions)
38 : BFormat(language, conventions)
39 {
40 }
41
42
BTimeFormat(const BTimeFormat & other)43 BTimeFormat::BTimeFormat(const BTimeFormat &other)
44 : BFormat(other)
45 {
46 }
47
48
~BTimeFormat()49 BTimeFormat::~BTimeFormat()
50 {
51 }
52
53
54 void
SetTimeFormat(BTimeFormatStyle style,const BString & format)55 BTimeFormat::SetTimeFormat(BTimeFormatStyle style,
56 const BString& format)
57 {
58 fConventions.SetExplicitTimeFormat(style, format);
59 }
60
61
62 // #pragma mark - Formatting
63
64
65 ssize_t
Format(char * string,size_t maxSize,time_t time,BTimeFormatStyle style) const66 BTimeFormat::Format(char* string, size_t maxSize, time_t time,
67 BTimeFormatStyle style) const
68 {
69 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
70 if (!timeFormatter.IsSet())
71 return B_NO_MEMORY;
72
73 UnicodeString icuString;
74 timeFormatter->format((UDate)time * 1000, icuString);
75
76 CheckedArrayByteSink stringConverter(string, maxSize);
77 icuString.toUTF8(stringConverter);
78
79 if (stringConverter.Overflowed())
80 return B_BAD_VALUE;
81
82 return stringConverter.NumberOfBytesWritten();
83 }
84
85
86 status_t
Format(BString & string,const time_t time,const BTimeFormatStyle style,const BTimeZone * timeZone) const87 BTimeFormat::Format(BString& string, const time_t time,
88 const BTimeFormatStyle style, const BTimeZone* timeZone) const
89 {
90 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
91 if (!timeFormatter.IsSet())
92 return B_NO_MEMORY;
93
94 if (timeZone != NULL) {
95 ObjectDeleter<TimeZone> icuTimeZone(
96 TimeZone::createTimeZone(timeZone->ID().String()));
97 if (!icuTimeZone.IsSet())
98 return B_NO_MEMORY;
99 timeFormatter->setTimeZone(*icuTimeZone.Get());
100 }
101
102 UnicodeString icuString;
103 timeFormatter->format((UDate)time * 1000, icuString);
104
105 string.Truncate(0);
106 BStringByteSink stringConverter(&string);
107 icuString.toUTF8(stringConverter);
108
109 return B_OK;
110 }
111
112
113 status_t
Format(BString & string,int * & fieldPositions,int & fieldCount,time_t time,BTimeFormatStyle style) const114 BTimeFormat::Format(BString& string, int*& fieldPositions, int& fieldCount,
115 time_t time, BTimeFormatStyle style) const
116 {
117 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
118 if (!timeFormatter.IsSet())
119 return B_NO_MEMORY;
120
121 fieldPositions = NULL;
122 UErrorCode error = U_ZERO_ERROR;
123 icu::FieldPositionIterator positionIterator;
124 UnicodeString icuString;
125 timeFormatter->format((UDate)time * 1000, icuString, &positionIterator,
126 error);
127
128 if (error != U_ZERO_ERROR)
129 return B_BAD_VALUE;
130
131 icu::FieldPosition field;
132 std::vector<int> fieldPosStorage;
133 fieldCount = 0;
134 while (positionIterator.next(field)) {
135 fieldPosStorage.push_back(field.getBeginIndex());
136 fieldPosStorage.push_back(field.getEndIndex());
137 fieldCount += 2;
138 }
139
140 fieldPositions = (int*) malloc(fieldCount * sizeof(int));
141
142 for (int i = 0 ; i < fieldCount ; i++ )
143 fieldPositions[i] = fieldPosStorage[i];
144
145 string.Truncate(0);
146 BStringByteSink stringConverter(&string);
147 icuString.toUTF8(stringConverter);
148
149 return B_OK;
150 }
151
152
153 status_t
GetTimeFields(BDateElement * & fields,int & fieldCount,BTimeFormatStyle style) const154 BTimeFormat::GetTimeFields(BDateElement*& fields, int& fieldCount,
155 BTimeFormatStyle style) const
156 {
157 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
158 if (!timeFormatter.IsSet())
159 return B_NO_MEMORY;
160
161 fields = NULL;
162 UErrorCode error = U_ZERO_ERROR;
163 icu::FieldPositionIterator positionIterator;
164 UnicodeString icuString;
165 time_t now;
166 timeFormatter->format((UDate)time(&now) * 1000, icuString,
167 &positionIterator, error);
168
169 if (error != U_ZERO_ERROR)
170 return B_BAD_VALUE;
171
172 icu::FieldPosition field;
173 std::vector<int> fieldPosStorage;
174 fieldCount = 0;
175 while (positionIterator.next(field)) {
176 fieldPosStorage.push_back(field.getField());
177 fieldCount ++;
178 }
179
180 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement));
181
182 for (int i = 0 ; i < fieldCount ; i++ ) {
183 switch (fieldPosStorage[i]) {
184 case UDAT_HOUR_OF_DAY1_FIELD:
185 case UDAT_HOUR_OF_DAY0_FIELD:
186 case UDAT_HOUR1_FIELD:
187 case UDAT_HOUR0_FIELD:
188 fields[i] = B_DATE_ELEMENT_HOUR;
189 break;
190 case UDAT_MINUTE_FIELD:
191 fields[i] = B_DATE_ELEMENT_MINUTE;
192 break;
193 case UDAT_SECOND_FIELD:
194 fields[i] = B_DATE_ELEMENT_SECOND;
195 break;
196 case UDAT_AM_PM_FIELD:
197 fields[i] = B_DATE_ELEMENT_AM_PM;
198 break;
199 default:
200 fields[i] = B_DATE_ELEMENT_INVALID;
201 break;
202 }
203 }
204
205 return B_OK;
206 }
207
208
209 status_t
Parse(BString source,BTimeFormatStyle style,BTime & output)210 BTimeFormat::Parse(BString source, BTimeFormatStyle style, BTime& output)
211 {
212 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style));
213 if (!timeFormatter.IsSet())
214 return B_NO_MEMORY;
215
216 // If no timezone is specified in the time string, assume GMT
217 timeFormatter->setTimeZone(*icu::TimeZone::getGMT());
218
219 ParsePosition p(0);
220 UDate date = timeFormatter->parse(UnicodeString::fromUTF8(source.String()),
221 p);
222
223 output.SetTime(0, 0, 0);
224 output.AddMilliseconds(date);
225
226 return B_OK;
227 }
228
229
230 DateFormat*
_CreateTimeFormatter(const BTimeFormatStyle style) const231 BTimeFormat::_CreateTimeFormatter(const BTimeFormatStyle style) const
232 {
233 Locale* icuLocale
234 = fConventions.UseStringsFromPreferredLanguage()
235 ? BLanguage::Private(&fLanguage).ICULocale()
236 : BFormattingConventions::Private(&fConventions).ICULocale();
237
238 icu::DateFormat* timeFormatter
239 = icu::DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale);
240 if (timeFormatter == NULL)
241 return NULL;
242
243 SimpleDateFormat* timeFormatterImpl
244 = static_cast<SimpleDateFormat*>(timeFormatter);
245
246 BString format;
247 fConventions.GetTimeFormat(style, format);
248
249 UnicodeString pattern(format.String());
250 timeFormatterImpl->applyPattern(pattern);
251
252 return timeFormatter;
253 }
254