2 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
3 * Distributed under the terms of the MIT License.
7 #include "ICUTimeData.h"
13 #include <unicode/dtfmtsym.h>
14 #include <unicode/gregocal.h>
15 #include <unicode/smpdtfmt.h>
17 #include <AutoDeleter.h>
19 #include "ICUMessagesData.h"
25 ICUTimeData::ICUTimeData(pthread_key_t tlsKey
, struct lc_time_t
& lcTimeInfo
,
26 const ICUMessagesData
& messagesData
)
29 fLCTimeInfo(lcTimeInfo
),
31 fMessagesData(messagesData
)
33 for (int i
= 0; i
< 12; ++i
) {
34 fLCTimeInfo
.mon
[i
] = fMon
[i
];
35 fLCTimeInfo
.month
[i
] = fMonth
[i
];
36 fLCTimeInfo
.alt_month
[i
] = fAltMonth
[i
];
38 for (int i
= 0; i
< 7; ++i
) {
39 fLCTimeInfo
.wday
[i
] = fWday
[i
];
40 fLCTimeInfo
.weekday
[i
] = fWeekday
[i
];
42 fLCTimeInfo
.X_fmt
= fTimeFormat
;
43 fLCTimeInfo
.x_fmt
= fDateFormat
;
44 fLCTimeInfo
.c_fmt
= fDateTimeFormat
;
47 fLCTimeInfo
.date_fmt
= fDateTimeZoneFormat
;
48 fLCTimeInfo
.md_order
= fMonthDayOrder
;
49 fLCTimeInfo
.ampm_fmt
= fAmPmFormat
;
53 ICUTimeData::~ICUTimeData()
59 ICUTimeData::Initialize(LocaleTimeDataBridge
* dataBridge
)
61 fDataBridge
= dataBridge
;
66 ICUTimeData::SetTo(const Locale
& locale
, const char* posixLocaleName
)
68 status_t result
= inherited::SetTo(locale
, posixLocaleName
);
72 UErrorCode icuStatus
= U_ZERO_ERROR
;
73 DateFormatSymbols
formatSymbols(ICULocaleForStrings(), icuStatus
);
74 if (!U_SUCCESS(icuStatus
))
78 const UnicodeString
* strings
= formatSymbols
.getShortMonths(count
);
79 result
= _SetLCTimeEntries(strings
, fMon
[0], sizeof(fMon
[0]), count
, 12);
82 strings
= formatSymbols
.getMonths(count
);
83 result
= _SetLCTimeEntries(strings
, fMonth
[0], sizeof(fMonth
[0]), count
,
88 strings
= formatSymbols
.getShortWeekdays(count
);
89 if (count
== 8 && strings
[0].length() == 0) {
90 // ICUs weekday arrays are 1-based
95 = _SetLCTimeEntries(strings
, fWday
[0], sizeof(fWday
[0]), count
, 7);
99 strings
= formatSymbols
.getWeekdays(count
);
100 if (count
== 8 && strings
[0].length() == 0) {
101 // ICUs weekday arrays are 1-based
105 result
= _SetLCTimeEntries(strings
, fWeekday
[0], sizeof(fWeekday
[0]),
109 if (result
== B_OK
) {
111 DateFormat
* format
= DateFormat::createTimeInstance(
112 DateFormat::kDefault
, fLocale
);
113 result
= _SetLCTimePattern(format
, fTimeFormat
, sizeof(fTimeFormat
));
116 result
= B_NO_MEMORY
;
120 if (result
== B_OK
) {
122 DateFormat
* format
= DateFormat::createDateInstance(
123 DateFormat::kDefault
, fLocale
);
124 result
= _SetLCTimePattern(format
, fDateFormat
, sizeof(fDateFormat
));
127 result
= B_NO_MEMORY
;
131 if (result
== B_OK
) {
133 DateFormat
* format
= DateFormat::createDateTimeInstance(
134 DateFormat::kFull
, DateFormat::kFull
, fLocale
);
135 result
= _SetLCTimePattern(format
, fDateTimeFormat
,
136 sizeof(fDateTimeFormat
));
139 result
= B_NO_MEMORY
;
143 if (result
== B_OK
) {
144 strings
= formatSymbols
.getAmPmStrings(count
);
145 result
= _SetLCTimeEntries(strings
, fAm
, sizeof(fAm
), 1, 1);
147 result
= _SetLCTimeEntries(&strings
[1], fPm
, sizeof(fPm
), 1, 1);
150 if (result
== B_OK
) {
151 strings
= formatSymbols
.getMonths(count
, DateFormatSymbols::STANDALONE
,
152 DateFormatSymbols::WIDE
);
153 result
= _SetLCTimeEntries(strings
, fAltMonth
[0], sizeof(fAltMonth
[0]),
157 strcpy(fAmPmFormat
, fDataBridge
->posixLCTimeInfo
->ampm_fmt
);
158 // ICU does not provide anything for this (and that makes sense, too)
165 ICUTimeData::SetToPosix()
167 status_t result
= inherited::SetToPosix();
169 if (result
== B_OK
) {
170 for (int i
= 0; i
< 12; ++i
) {
171 strcpy(fMon
[i
], fDataBridge
->posixLCTimeInfo
->mon
[i
]);
172 strcpy(fMonth
[i
], fDataBridge
->posixLCTimeInfo
->month
[i
]);
173 strcpy(fAltMonth
[i
], fDataBridge
->posixLCTimeInfo
->alt_month
[i
]);
175 for (int i
= 0; i
< 7; ++i
) {
176 strcpy(fWday
[i
], fDataBridge
->posixLCTimeInfo
->wday
[i
]);
177 strcpy(fWeekday
[i
], fDataBridge
->posixLCTimeInfo
->weekday
[i
]);
179 strcpy(fTimeFormat
, fDataBridge
->posixLCTimeInfo
->X_fmt
);
180 strcpy(fDateFormat
, fDataBridge
->posixLCTimeInfo
->x_fmt
);
181 strcpy(fDateTimeFormat
, fDataBridge
->posixLCTimeInfo
->c_fmt
);
182 strcpy(fAm
, fDataBridge
->posixLCTimeInfo
->am
);
183 strcpy(fPm
, fDataBridge
->posixLCTimeInfo
->pm
);
184 strcpy(fDateTimeZoneFormat
, fDataBridge
->posixLCTimeInfo
->date_fmt
);
185 strcpy(fMonthDayOrder
, fDataBridge
->posixLCTimeInfo
->md_order
);
186 strcpy(fAmPmFormat
, fDataBridge
->posixLCTimeInfo
->ampm_fmt
);
194 ICUTimeData::GetLanginfo(int index
)
198 return fDateTimeFormat
;
217 return fWeekday
[index
- DAY_1
];
226 return fWday
[index
- ABDAY_1
];
240 return fMonth
[index
- MON_1
];
254 return fMon
[index
- ABMON_1
];
263 ICUTimeData::ICULocaleForStrings() const
265 // check if the date strings should be taken from the messages-locale
266 // or from the time-locale (default)
267 UErrorCode icuStatus
= U_ZERO_ERROR
;
268 char stringsValue
[16];
269 fLocale
.getKeywordValue("strings", stringsValue
, sizeof(stringsValue
),
271 if (U_SUCCESS(icuStatus
) && strcasecmp(stringsValue
, "messages") == 0)
272 return fMessagesData
.ICULocale();
279 ICUTimeData::_SetLCTimeEntries(const UnicodeString
* strings
, char* destination
,
280 int entrySize
, int count
, int maxCount
)
285 status_t result
= B_OK
;
286 if (count
> maxCount
)
288 for (int32 i
= 0; result
== B_OK
&& i
< count
; ++i
) {
289 result
= _ConvertUnicodeStringToLocaleconvEntry(strings
[i
], destination
,
291 destination
+= entrySize
;
299 ICUTimeData::_SetLCTimePattern(DateFormat
* format
, char* destination
,
302 SimpleDateFormat
* simpleFormat
= dynamic_cast<SimpleDateFormat
*>(format
);
306 // convert ICU-type pattern to posix (i.e. strftime()) format string
307 UnicodeString icuPattern
;
308 simpleFormat
->toPattern(icuPattern
);
309 UnicodeString posixPattern
;
310 if (icuPattern
.length() > 0) {
311 UChar lastCharSeen
= 0;
312 int lastCharCount
= 1;
313 bool inSingleQuotes
= false;
314 bool inDoubleQuotes
= false;
315 // we loop one character past the end on purpose, which will result in a
316 // final -1 char to be processed, which in turn will let us handle the
317 // last character (via lastCharSeen)
318 for (int i
= 0; i
<= icuPattern
.length(); ++i
) {
319 UChar currChar
= icuPattern
.charAt(i
);
320 if (lastCharSeen
!= 0 && currChar
== lastCharSeen
) {
325 if (!inSingleQuotes
&& !inDoubleQuotes
) {
326 switch (lastCharSeen
) {
328 posixPattern
.append(UnicodeString("%p", ""));
331 if (lastCharCount
== 2)
332 posixPattern
.append(UnicodeString("%d", ""));
334 posixPattern
.append(UnicodeString("%e", ""));
337 posixPattern
.append(UnicodeString("%j", ""));
340 // fall through, to handle 'c' the same as 'e'
342 if (lastCharCount
== 4)
343 posixPattern
.append(UnicodeString("%A", ""));
344 else if (lastCharCount
<= 2)
345 posixPattern
.append(UnicodeString("%u", ""));
347 posixPattern
.append(UnicodeString("%a", ""));
350 if (lastCharCount
== 4)
351 posixPattern
.append(UnicodeString("%A", ""));
353 posixPattern
.append(UnicodeString("%a", ""));
356 // fall through, to handle 'k' the same as 'h'
358 if (lastCharCount
== 2)
359 posixPattern
.append(UnicodeString("%I", ""));
361 posixPattern
.append(UnicodeString("%l", ""));
364 if (lastCharCount
== 2)
365 posixPattern
.append(UnicodeString("%H", ""));
367 posixPattern
.append(UnicodeString("%k", ""));
370 posixPattern
.append(UnicodeString("%M", ""));
373 // fall through, to handle 'L' the same as 'M'
375 if (lastCharCount
== 4)
376 posixPattern
.append(UnicodeString("%B", ""));
377 else if (lastCharCount
== 3)
378 posixPattern
.append(UnicodeString("%b", ""));
380 posixPattern
.append(UnicodeString("%m", ""));
383 posixPattern
.append(UnicodeString("%S", ""));
386 posixPattern
.append(UnicodeString("%V", ""));
389 if (lastCharCount
== 2)
390 posixPattern
.append(UnicodeString("%y", ""));
392 posixPattern
.append(UnicodeString("%Y", ""));
395 posixPattern
.append(UnicodeString("%G", ""));
398 posixPattern
.append(UnicodeString("%Z", ""));
401 posixPattern
.append(UnicodeString("%z", ""));
404 if (lastCharSeen
!= 0)
405 posixPattern
.append(lastCharSeen
);
408 if (lastCharSeen
!= 0)
409 posixPattern
.append(lastCharSeen
);
412 if (currChar
== L
'"') {
413 inDoubleQuotes
= !inDoubleQuotes
;
415 } else if (currChar
== L
'\'') {
416 inSingleQuotes
= !inSingleQuotes
;
419 lastCharSeen
= currChar
;
425 return _ConvertUnicodeStringToLocaleconvEntry(posixPattern
, destination
,
430 } // namespace Libroot
431 } // namespace BPrivate