]> git.saurik.com Git - apple/cf.git/blob - CFDateFormatter.c
CF-550.tar.gz
[apple/cf.git] / CFDateFormatter.c
1 /*
2 * Copyright (c) 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* CFDateFormatter.c
24 Copyright (c) 2002-2009, Apple Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #include <CoreFoundation/CFDateFormatter.h>
29 #include <CoreFoundation/CFDate.h>
30 #include <CoreFoundation/CFTimeZone.h>
31 #include <CoreFoundation/CFCalendar.h>
32 #include <CoreFoundation/CFNumber.h>
33 #include "CFInternal.h"
34 #include "CFLocaleInternal.h"
35 #include <unicode/udat.h>
36 #include <unicode/udatpg.h>
37 #include <math.h>
38 #include <float.h>
39
40 extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz);
41 static void __CFDateFormatterCustomize(CFDateFormatterRef formatter);
42
43 CF_EXPORT const CFStringRef kCFDateFormatterCalendarIdentifierKey;
44
45 #undef CFReleaseIfNotNull
46 #define CFReleaseIfNotNull(X) if (X) CFRelease(X)
47
48 #define BUFFER_SIZE 768
49
50 CFStringRef CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator, CFStringRef tmplate, CFOptionFlags options, CFLocaleRef locale) {
51 if (allocator) __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
52 if (locale) __CFGenericValidateType(locale, CFLocaleGetTypeID());
53 __CFGenericValidateType(tmplate, CFStringGetTypeID());
54
55 CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR("");
56 char buffer[BUFFER_SIZE];
57 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
58 if (NULL == cstr) {
59 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
60 }
61 if (NULL == cstr) {
62 return NULL;
63 }
64
65 UErrorCode status = U_ZERO_ERROR;
66 UDateTimePatternGenerator *ptg = udatpg_open(cstr, &status);
67 if (NULL == ptg || U_FAILURE(status)) {
68 return NULL;
69 }
70
71 CFIndex jCount = 0; // the only interesting cases are 0, 1, and 2 (adjacent)
72 CFRange r = CFStringFind(tmplate, CFSTR("j"), 0);
73 if (kCFNotFound != r.location) {
74 jCount++;
75 if ((r.location + 1 < CFStringGetLength(tmplate)) && ('j' == CFStringGetCharacterAtIndex(tmplate, r.location + 1))) {
76 jCount++;
77 }
78 }
79
80 UChar pattern[BUFFER_SIZE], skel[BUFFER_SIZE], bpat[BUFFER_SIZE];
81 CFIndex cnt = CFStringGetLength(tmplate);
82 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
83 CFStringGetCharacters(tmplate, CFRangeMake(0, cnt), (UniChar *)pattern);
84 int32_t patlen = cnt;
85
86 status = U_ZERO_ERROR;
87 int32_t skellen = udatpg_getSkeleton(ptg, pattern, patlen, skel, sizeof(skel) / sizeof(skel[0]), &status);
88 if (U_FAILURE(status)) {
89 return NULL;
90 }
91
92 if ((0 < jCount) && (skellen + jCount < (sizeof(skel) / sizeof(skel[0])))) {
93 skel[skellen++] = 'j';
94 if (1 < jCount) skel[skellen++] = 'j';
95 }
96
97 status = U_ZERO_ERROR;
98 int32_t bpatlen = udatpg_getBestPattern(ptg, skel, skellen, bpat, sizeof(bpat) / sizeof(bpat[0]), &status);
99 if (U_FAILURE(status)) {
100 return NULL;
101 }
102 udatpg_close(ptg);
103
104 return CFStringCreateWithCharacters(allocator, (const UniChar *)bpat, bpatlen);
105 }
106
107 struct __CFDateFormatter {
108 CFRuntimeBase _base;
109 UDateFormat *_df;
110 CFLocaleRef _locale;
111 CFDateFormatterStyle _timeStyle;
112 CFDateFormatterStyle _dateStyle;
113 CFStringRef _format;
114 CFStringRef _defformat;
115 struct {
116 CFBooleanRef _IsLenient;
117 CFBooleanRef _DoesRelativeDateFormatting;
118 CFBooleanRef _HasCustomFormat;
119 CFTimeZoneRef _TimeZone;
120 CFCalendarRef _Calendar;
121 CFStringRef _CalendarName;
122 CFDateRef _TwoDigitStartDate;
123 CFDateRef _DefaultDate;
124 CFDateRef _GregorianStartDate;
125 CFArrayRef _EraSymbols;
126 CFArrayRef _LongEraSymbols;
127 CFArrayRef _MonthSymbols;
128 CFArrayRef _ShortMonthSymbols;
129 CFArrayRef _VeryShortMonthSymbols;
130 CFArrayRef _StandaloneMonthSymbols;
131 CFArrayRef _ShortStandaloneMonthSymbols;
132 CFArrayRef _VeryShortStandaloneMonthSymbols;
133 CFArrayRef _WeekdaySymbols;
134 CFArrayRef _ShortWeekdaySymbols;
135 CFArrayRef _VeryShortWeekdaySymbols;
136 CFArrayRef _StandaloneWeekdaySymbols;
137 CFArrayRef _ShortStandaloneWeekdaySymbols;
138 CFArrayRef _VeryShortStandaloneWeekdaySymbols;
139 CFArrayRef _QuarterSymbols;
140 CFArrayRef _ShortQuarterSymbols;
141 CFArrayRef _StandaloneQuarterSymbols;
142 CFArrayRef _ShortStandaloneQuarterSymbols;
143 CFStringRef _AMSymbol;
144 CFStringRef _PMSymbol;
145 } _property;
146 };
147
148 static CFStringRef __CFDateFormatterCopyDescription(CFTypeRef cf) {
149 CFDateFormatterRef formatter = (CFDateFormatterRef)cf;
150 return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR("<CFDateFormatter %p [%p]>"), cf, CFGetAllocator(formatter));
151 }
152
153 static void __CFDateFormatterDeallocate(CFTypeRef cf) {
154 CFDateFormatterRef formatter = (CFDateFormatterRef)cf;
155 if (formatter->_df) udat_close(formatter->_df);
156 if (formatter->_locale) CFRelease(formatter->_locale);
157 if (formatter->_format) CFRelease(formatter->_format);
158 if (formatter->_defformat) CFRelease(formatter->_defformat);
159 CFReleaseIfNotNull(formatter->_property._IsLenient);
160 CFReleaseIfNotNull(formatter->_property._DoesRelativeDateFormatting);
161 CFReleaseIfNotNull(formatter->_property._TimeZone);
162 CFReleaseIfNotNull(formatter->_property._Calendar);
163 CFReleaseIfNotNull(formatter->_property._CalendarName);
164 CFReleaseIfNotNull(formatter->_property._TwoDigitStartDate);
165 CFReleaseIfNotNull(formatter->_property._DefaultDate);
166 CFReleaseIfNotNull(formatter->_property._GregorianStartDate);
167 CFReleaseIfNotNull(formatter->_property._EraSymbols);
168 CFReleaseIfNotNull(formatter->_property._LongEraSymbols);
169 CFReleaseIfNotNull(formatter->_property._MonthSymbols);
170 CFReleaseIfNotNull(formatter->_property._ShortMonthSymbols);
171 CFReleaseIfNotNull(formatter->_property._VeryShortMonthSymbols);
172 CFReleaseIfNotNull(formatter->_property._StandaloneMonthSymbols);
173 CFReleaseIfNotNull(formatter->_property._ShortStandaloneMonthSymbols);
174 CFReleaseIfNotNull(formatter->_property._VeryShortStandaloneMonthSymbols);
175 CFReleaseIfNotNull(formatter->_property._WeekdaySymbols);
176 CFReleaseIfNotNull(formatter->_property._ShortWeekdaySymbols);
177 CFReleaseIfNotNull(formatter->_property._VeryShortWeekdaySymbols);
178 CFReleaseIfNotNull(formatter->_property._StandaloneWeekdaySymbols);
179 CFReleaseIfNotNull(formatter->_property._ShortStandaloneWeekdaySymbols);
180 CFReleaseIfNotNull(formatter->_property._VeryShortStandaloneWeekdaySymbols);
181 CFReleaseIfNotNull(formatter->_property._QuarterSymbols);
182 CFReleaseIfNotNull(formatter->_property._ShortQuarterSymbols);
183 CFReleaseIfNotNull(formatter->_property._StandaloneQuarterSymbols);
184 CFReleaseIfNotNull(formatter->_property._ShortStandaloneQuarterSymbols);
185 CFReleaseIfNotNull(formatter->_property._AMSymbol);
186 CFReleaseIfNotNull(formatter->_property._PMSymbol);
187 }
188
189 static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef formatter, CFStringRef inString);
190
191 static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value, Boolean directToICU);
192
193 #define RESET_PROPERTY(C, K) \
194 if (df->_property. C) __CFDateFormatterSetProperty(df, K, df->_property. C, true);
195
196 static void __ResetUDateFormat(CFDateFormatterRef df, Boolean goingToHaveCustomFormat) {
197 if (df->_df) udat_close(df->_df);
198 df->_df = NULL;
199
200 // uses _timeStyle, _dateStyle, _locale, _property._TimeZone; sets _df, _format, _defformat
201 char loc_buffer[BUFFER_SIZE];
202 loc_buffer[0] = 0;
203 CFStringRef tmpLocName = df->_locale ? CFLocaleGetIdentifier(df->_locale) : CFSTR("");
204 CFStringGetCString(tmpLocName, loc_buffer, BUFFER_SIZE, kCFStringEncodingASCII);
205
206 UChar tz_buffer[BUFFER_SIZE];
207 tz_buffer[0] = 0;
208 CFStringRef tmpTZName = df->_property._TimeZone ? CFTimeZoneGetName(df->_property._TimeZone) : CFSTR("GMT");
209 CFStringGetCharacters(tmpTZName, CFRangeMake(0, CFStringGetLength(tmpTZName)), (UniChar *)tz_buffer);
210
211 df->_property._HasCustomFormat = kCFBooleanFalse;
212
213 int32_t udstyle = 0, utstyle = 0;
214 switch (df->_dateStyle) {
215 case kCFDateFormatterNoStyle: udstyle = UDAT_NONE; break;
216 case kCFDateFormatterShortStyle: udstyle = UDAT_SHORT; break;
217 case kCFDateFormatterMediumStyle: udstyle = UDAT_MEDIUM; break;
218 case kCFDateFormatterLongStyle: udstyle = UDAT_LONG; break;
219 case kCFDateFormatterFullStyle: udstyle = UDAT_FULL; break;
220 }
221 switch (df->_timeStyle) {
222 case kCFDateFormatterNoStyle: utstyle = UDAT_NONE; break;
223 case kCFDateFormatterShortStyle: utstyle = UDAT_SHORT; break;
224 case kCFDateFormatterMediumStyle: utstyle = UDAT_MEDIUM; break;
225 case kCFDateFormatterLongStyle: utstyle = UDAT_LONG; break;
226 case kCFDateFormatterFullStyle: utstyle = UDAT_FULL; break;
227 }
228 Boolean wantRelative = (NULL != df->_property._DoesRelativeDateFormatting && df->_property._DoesRelativeDateFormatting == kCFBooleanTrue);
229 Boolean hasFormat = (NULL != df->_property._HasCustomFormat && df->_property._HasCustomFormat == kCFBooleanTrue) || goingToHaveCustomFormat;
230 if (wantRelative && !hasFormat) {
231 udstyle |= UDAT_RELATIVE;
232 }
233
234 UErrorCode status = U_ZERO_ERROR;
235 UDateFormat *icudf = udat_open((UDateFormatStyle)utstyle, (UDateFormatStyle)udstyle, loc_buffer, tz_buffer, CFStringGetLength(tmpTZName), NULL, 0, &status);
236 if (NULL == icudf || U_FAILURE(status)) {
237 return;
238 }
239 udat_setLenient(icudf, 0);
240 if (kCFDateFormatterNoStyle == df->_dateStyle && kCFDateFormatterNoStyle == df->_timeStyle) {
241 udat_applyPattern(icudf, false, NULL, 0);
242 }
243 CFStringRef calident = (CFStringRef)CFLocaleGetValue(df->_locale, kCFLocaleCalendarIdentifierKey);
244 if (calident && CFEqual(calident, kCFCalendarIdentifierGregorian)) {
245 status = U_ZERO_ERROR;
246 udat_set2DigitYearStart(icudf, -631152000000.0, &status); // 1950-01-01 00:00:00 GMT
247 }
248 df->_df = icudf;
249
250 __CFDateFormatterCustomize(df);
251
252 UChar ubuffer[BUFFER_SIZE];
253 status = U_ZERO_ERROR;
254 int32_t ret = udat_toPattern(icudf, false, ubuffer, BUFFER_SIZE, &status);
255 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
256 CFStringRef newFormat = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ret);
257 CFStringRef formatString = __CFDateFormatterCreateForcedString(df, newFormat);
258 CFIndex cnt = CFStringGetLength(formatString);
259 CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__);
260 if (df->_format != formatString && cnt <= 1024) {
261 STACK_BUFFER_DECL(UChar, ubuffer, cnt);
262 const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString);
263 if (NULL == ustr) {
264 CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer);
265 ustr = ubuffer;
266 }
267 UErrorCode status = U_ZERO_ERROR;
268 // udat_applyPattern(df->_df, false, ustr, cnt, &status);
269 udat_applyPattern(df->_df, false, ustr, cnt);
270 if (U_SUCCESS(status)) {
271 if (df->_format) CFRelease(df->_format);
272 df->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(df), formatString);
273 }
274 }
275 CFRelease(formatString);
276 CFRelease(newFormat);
277 }
278 if (df->_defformat) CFRelease(df->_defformat);
279 df->_defformat = df->_format ? (CFStringRef)CFRetain(df->_format) : NULL;
280
281 RESET_PROPERTY(_IsLenient, kCFDateFormatterIsLenientKey);
282 RESET_PROPERTY(_DoesRelativeDateFormatting, kCFDateFormatterDoesRelativeDateFormattingKey);
283 RESET_PROPERTY(_Calendar, kCFDateFormatterCalendarKey);
284 RESET_PROPERTY(_CalendarName, kCFDateFormatterCalendarIdentifierKey);
285 RESET_PROPERTY(_TimeZone, kCFDateFormatterTimeZoneKey);
286 RESET_PROPERTY(_TwoDigitStartDate, kCFDateFormatterTwoDigitStartDateKey);
287 RESET_PROPERTY(_DefaultDate, kCFDateFormatterDefaultDateKey);
288 RESET_PROPERTY(_GregorianStartDate, kCFDateFormatterGregorianStartDateKey);
289 RESET_PROPERTY(_EraSymbols, kCFDateFormatterEraSymbolsKey);
290 RESET_PROPERTY(_LongEraSymbols, kCFDateFormatterLongEraSymbolsKey);
291 RESET_PROPERTY(_MonthSymbols, kCFDateFormatterMonthSymbolsKey);
292 RESET_PROPERTY(_ShortMonthSymbols, kCFDateFormatterShortMonthSymbolsKey);
293 RESET_PROPERTY(_VeryShortMonthSymbols, kCFDateFormatterVeryShortMonthSymbolsKey);
294 RESET_PROPERTY(_StandaloneMonthSymbols, kCFDateFormatterStandaloneMonthSymbolsKey);
295 RESET_PROPERTY(_ShortStandaloneMonthSymbols, kCFDateFormatterShortStandaloneMonthSymbolsKey);
296 RESET_PROPERTY(_VeryShortStandaloneMonthSymbols, kCFDateFormatterVeryShortStandaloneMonthSymbolsKey);
297 RESET_PROPERTY(_WeekdaySymbols, kCFDateFormatterWeekdaySymbolsKey);
298 RESET_PROPERTY(_ShortWeekdaySymbols, kCFDateFormatterShortWeekdaySymbolsKey);
299 RESET_PROPERTY(_VeryShortWeekdaySymbols, kCFDateFormatterVeryShortWeekdaySymbolsKey);
300 RESET_PROPERTY(_StandaloneWeekdaySymbols, kCFDateFormatterStandaloneWeekdaySymbolsKey);
301 RESET_PROPERTY(_ShortStandaloneWeekdaySymbols, kCFDateFormatterShortStandaloneWeekdaySymbolsKey);
302 RESET_PROPERTY(_VeryShortStandaloneWeekdaySymbols, kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey);
303 RESET_PROPERTY(_QuarterSymbols, kCFDateFormatterQuarterSymbolsKey);
304 RESET_PROPERTY(_ShortQuarterSymbols, kCFDateFormatterShortQuarterSymbolsKey);
305 RESET_PROPERTY(_StandaloneQuarterSymbols, kCFDateFormatterStandaloneQuarterSymbolsKey);
306 RESET_PROPERTY(_ShortStandaloneQuarterSymbols, kCFDateFormatterShortStandaloneQuarterSymbolsKey);
307 RESET_PROPERTY(_AMSymbol, kCFDateFormatterAMSymbolKey);
308 RESET_PROPERTY(_PMSymbol, kCFDateFormatterPMSymbolKey);
309 }
310
311 static CFTypeID __kCFDateFormatterTypeID = _kCFRuntimeNotATypeID;
312
313 static const CFRuntimeClass __CFDateFormatterClass = {
314 0,
315 "CFDateFormatter",
316 NULL, // init
317 NULL, // copy
318 __CFDateFormatterDeallocate,
319 NULL,
320 NULL,
321 NULL, //
322 __CFDateFormatterCopyDescription
323 };
324
325 static void __CFDateFormatterInitialize(void) {
326 __kCFDateFormatterTypeID = _CFRuntimeRegisterClass(&__CFDateFormatterClass);
327 }
328
329 CFTypeID CFDateFormatterGetTypeID(void) {
330 if (_kCFRuntimeNotATypeID == __kCFDateFormatterTypeID) __CFDateFormatterInitialize();
331 return __kCFDateFormatterTypeID;
332 }
333
334 CFDateFormatterRef CFDateFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFDateFormatterStyle dateStyle, CFDateFormatterStyle timeStyle) {
335 struct __CFDateFormatter *memory;
336 uint32_t size = sizeof(struct __CFDateFormatter) - sizeof(CFRuntimeBase);
337 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
338 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
339 if (locale) __CFGenericValidateType(locale, CFLocaleGetTypeID());
340 memory = (struct __CFDateFormatter *)_CFRuntimeCreateInstance(allocator, CFDateFormatterGetTypeID(), size, NULL);
341 if (NULL == memory) {
342 return NULL;
343 }
344 memory->_df = NULL;
345 memory->_locale = NULL;
346 memory->_format = NULL;
347 memory->_defformat = NULL;
348 memory->_dateStyle = dateStyle;
349 memory->_timeStyle = timeStyle;
350 memory->_property._IsLenient = NULL;
351 memory->_property._DoesRelativeDateFormatting = NULL;
352 memory->_property._HasCustomFormat = NULL;
353 memory->_property._TimeZone = NULL;
354 memory->_property._Calendar = NULL;
355 memory->_property._CalendarName = NULL;
356 memory->_property._TwoDigitStartDate = NULL;
357 memory->_property._DefaultDate = NULL;
358 memory->_property._GregorianStartDate = NULL;
359 memory->_property._EraSymbols = NULL;
360 memory->_property._LongEraSymbols = NULL;
361 memory->_property._MonthSymbols = NULL;
362 memory->_property._ShortMonthSymbols = NULL;
363 memory->_property._VeryShortMonthSymbols = NULL;
364 memory->_property._StandaloneMonthSymbols = NULL;
365 memory->_property._ShortStandaloneMonthSymbols = NULL;
366 memory->_property._VeryShortStandaloneMonthSymbols = NULL;
367 memory->_property._WeekdaySymbols = NULL;
368 memory->_property._ShortWeekdaySymbols = NULL;
369 memory->_property._VeryShortWeekdaySymbols = NULL;
370 memory->_property._StandaloneWeekdaySymbols = NULL;
371 memory->_property._ShortStandaloneWeekdaySymbols = NULL;
372 memory->_property._VeryShortStandaloneWeekdaySymbols = NULL;
373 memory->_property._QuarterSymbols = NULL;
374 memory->_property._ShortQuarterSymbols = NULL;
375 memory->_property._StandaloneQuarterSymbols = NULL;
376 memory->_property._ShortStandaloneQuarterSymbols = NULL;
377 memory->_property._AMSymbol = NULL;
378 memory->_property._PMSymbol = NULL;
379
380 switch (dateStyle) {
381 case kCFDateFormatterNoStyle:
382 case kCFDateFormatterShortStyle:
383 case kCFDateFormatterMediumStyle:
384 case kCFDateFormatterLongStyle:
385 case kCFDateFormatterFullStyle: break;
386 default:
387 CFAssert2(0, __kCFLogAssertion, "%s(): unknown date style %d", __PRETTY_FUNCTION__, dateStyle);
388 memory->_dateStyle = kCFDateFormatterMediumStyle;
389 break;
390 }
391 switch (timeStyle) {
392 case kCFDateFormatterNoStyle:
393 case kCFDateFormatterShortStyle:
394 case kCFDateFormatterMediumStyle:
395 case kCFDateFormatterLongStyle:
396 case kCFDateFormatterFullStyle: break;
397 default:
398 CFAssert2(0, __kCFLogAssertion, "%s(): unknown time style %d", __PRETTY_FUNCTION__, timeStyle);
399 memory->_timeStyle = kCFDateFormatterMediumStyle;
400 break;
401 }
402
403 memory->_locale = locale ? CFLocaleCreateCopy(allocator, locale) : (CFLocaleRef)CFRetain(CFLocaleGetSystem());
404 memory->_property._TimeZone = CFTimeZoneCopyDefault();
405 __ResetUDateFormat(memory, false);
406 if (!memory->_df) {
407 CFRelease(memory);
408 return NULL;
409 }
410 return (CFDateFormatterRef)memory;
411 }
412
413 extern CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale);
414
415 static void __substituteFormatStringFromPrefsDFRelative(CFDateFormatterRef formatter) {
416 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
417
418 CFIndex dateLen = -1;
419 UChar dateBuffer[BUFFER_SIZE];
420 if (kCFDateFormatterNoStyle != formatter->_dateStyle) {
421 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUDateFormatStrings")) : NULL;
422 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
423 CFStringRef key;
424 switch (formatter->_dateStyle) {
425 case kCFDateFormatterShortStyle: key = CFSTR("1"); break;
426 case kCFDateFormatterMediumStyle: key = CFSTR("2"); break;
427 case kCFDateFormatterLongStyle: key = CFSTR("3"); break;
428 case kCFDateFormatterFullStyle: key = CFSTR("4"); break;
429 default: key = CFSTR("0"); break;
430 }
431 CFStringRef pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key);
432 if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) {
433 dateLen = __CFMin(CFStringGetLength(pref), BUFFER_SIZE);
434 CFStringGetCharacters(pref, CFRangeMake(0, dateLen), (UniChar *)dateBuffer);
435 }
436 }
437 }
438 if (-1 == dateLen) {
439 UErrorCode status = U_ZERO_ERROR;
440 int32_t ret = udat_toPatternRelativeDate(formatter->_df, dateBuffer, BUFFER_SIZE, &status);
441 if (!U_FAILURE(status)) {
442 dateLen = ret;
443 }
444 }
445
446 CFIndex timeLen = -1;
447 UChar timeBuffer[BUFFER_SIZE];
448 if (kCFDateFormatterNoStyle != formatter->_timeStyle) {
449 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUTimeFormatStrings")) : NULL;
450 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
451 CFStringRef key;
452 switch (formatter->_timeStyle) {
453 case kCFDateFormatterShortStyle: key = CFSTR("1"); break;
454 case kCFDateFormatterMediumStyle: key = CFSTR("2"); break;
455 case kCFDateFormatterLongStyle: key = CFSTR("3"); break;
456 case kCFDateFormatterFullStyle: key = CFSTR("4"); break;
457 default: key = CFSTR("0"); break;
458 }
459 CFStringRef pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key);
460 if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) {
461 timeLen = __CFMin(CFStringGetLength(pref), BUFFER_SIZE);
462 CFStringGetCharacters(pref, CFRangeMake(0, timeLen), (UniChar *)timeBuffer);
463 }
464 }
465 }
466 if (-1 == timeLen) {
467 UErrorCode status = U_ZERO_ERROR;
468 int32_t ret = udat_toPatternRelativeTime(formatter->_df, timeBuffer, BUFFER_SIZE, &status);
469 if (!U_FAILURE(status)) {
470 timeLen = ret;
471 }
472 }
473
474 UErrorCode status = U_ZERO_ERROR;
475 udat_applyPatternRelative(formatter->_df, (0 <= dateLen) ? dateBuffer : NULL, (0 <= dateLen) ? dateLen : 0, (0 <= timeLen) ? timeBuffer : NULL, (0 <= timeLen) ? timeLen : 0, &status);
476 }
477
478 static void __substituteFormatStringFromPrefsDF(CFDateFormatterRef formatter, bool doTime) {
479 CFIndex formatStyle = doTime ? formatter->_timeStyle : formatter->_dateStyle;
480 CFStringRef prefName = doTime ? CFSTR("AppleICUTimeFormatStrings") : CFSTR("AppleICUDateFormatStrings");
481 if (kCFDateFormatterNoStyle != formatStyle) {
482 CFStringRef pref = NULL;
483 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
484 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, prefName) : NULL;
485 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
486 CFStringRef key;
487 switch (formatStyle) {
488 case kCFDateFormatterShortStyle: key = CFSTR("1"); break;
489 case kCFDateFormatterMediumStyle: key = CFSTR("2"); break;
490 case kCFDateFormatterLongStyle: key = CFSTR("3"); break;
491 case kCFDateFormatterFullStyle: key = CFSTR("4"); break;
492 default: key = CFSTR("0"); break;
493 }
494 pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key);
495 }
496 if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) {
497 int32_t icustyle = UDAT_NONE;
498 switch (formatStyle) {
499 case kCFDateFormatterShortStyle: icustyle = UDAT_SHORT; break;
500 case kCFDateFormatterMediumStyle: icustyle = UDAT_MEDIUM; break;
501 case kCFDateFormatterLongStyle: icustyle = UDAT_LONG; break;
502 case kCFDateFormatterFullStyle: icustyle = UDAT_FULL; break;
503 }
504 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
505 char buffer[BUFFER_SIZE];
506 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
507 if (NULL == cstr) {
508 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
509 }
510 UErrorCode status = U_ZERO_ERROR;
511 UDateFormat *df = udat_open((UDateFormatStyle)(doTime ? icustyle : UDAT_NONE), (UDateFormatStyle)(doTime ? UDAT_NONE : icustyle), cstr, NULL, 0, NULL, 0, &status);
512 if (NULL != df) {
513 UChar ubuffer[BUFFER_SIZE];
514 status = U_ZERO_ERROR;
515 int32_t date_len = udat_toPattern(df, false, ubuffer, BUFFER_SIZE, &status);
516 if (U_SUCCESS(status) && date_len <= BUFFER_SIZE) {
517 CFStringRef dateString = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)ubuffer, date_len);
518 status = U_ZERO_ERROR;
519 int32_t formatter_len = udat_toPattern(formatter->_df, false, ubuffer, BUFFER_SIZE, &status);
520 if (U_SUCCESS(status) && formatter_len <= BUFFER_SIZE) {
521 CFMutableStringRef formatString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
522 CFStringAppendCharacters(formatString, (UniChar *)ubuffer, formatter_len);
523 // find dateString inside formatString, substitute the pref in that range
524 CFRange result;
525 if (CFStringFindWithOptions(formatString, dateString, CFRangeMake(0, formatter_len), 0, &result)) {
526 CFStringReplace(formatString, result, pref);
527 int32_t new_len = CFStringGetLength(formatString);
528 STACK_BUFFER_DECL(UChar, new_buffer, new_len);
529 const UChar *new_ustr = (UChar *)CFStringGetCharactersPtr(formatString);
530 if (NULL == new_ustr) {
531 CFStringGetCharacters(formatString, CFRangeMake(0, new_len), (UniChar *)new_buffer);
532 new_ustr = new_buffer;
533 }
534 status = U_ZERO_ERROR;
535 // udat_applyPattern(formatter->_df, false, new_ustr, new_len, &status);
536 udat_applyPattern(formatter->_df, false, new_ustr, new_len);
537 }
538 CFRelease(formatString);
539 }
540 CFRelease(dateString);
541 }
542 udat_close(df);
543 }
544 }
545 }
546 }
547
548 static void __CFDateFormatterApplySymbolPrefs(const void *key, const void *value, void *context) {
549 if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFArrayGetTypeID()) {
550 CFDateFormatterRef formatter = (CFDateFormatterRef)context;
551 UDateFormatSymbolType sym = (UDateFormatSymbolType)CFStringGetIntValue((CFStringRef)key);
552 CFArrayRef array = (CFArrayRef)value;
553 CFIndex idx, cnt = CFArrayGetCount(array);
554 for (idx = 0; idx < cnt; idx++) {
555 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
556 if (CFGetTypeID(item) != CFStringGetTypeID()) continue;
557 CFIndex item_cnt = CFStringGetLength(item);
558 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
559 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item);
560 if (NULL == item_ustr) {
561 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
562 CFStringGetCharacters(item, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
563 item_ustr = item_buffer;
564 }
565 UErrorCode status = U_ZERO_ERROR;
566 udat_setSymbols(formatter->_df, sym, idx, item_ustr, item_cnt, &status);
567 }
568 }
569 }
570
571 static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef formatter, CFStringRef inString) {
572 if (!inString) return NULL;
573 Boolean doForce24 = false, doForce12 = false;
574 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
575 CFPropertyListRef pref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce24HourTime")) : NULL;
576 if (NULL != pref && CFGetTypeID(pref) == CFBooleanGetTypeID()) {
577 doForce24 = CFBooleanGetValue((CFBooleanRef)pref);
578 }
579 pref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce12HourTime")) : NULL;
580 if (NULL != pref && CFGetTypeID(pref) == CFBooleanGetTypeID()) {
581 doForce12 = CFBooleanGetValue((CFBooleanRef)pref);
582 }
583 if (!doForce24 && !doForce12) return (CFStringRef)CFRetain(inString);
584 if (doForce24) doForce12 = false; // if both are set, Force24 wins, period
585 CFMutableStringRef outString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
586 CFIndex cnt = CFStringGetLength(inString);
587 CFIndex lastSecond = -1, lastMinute = -1, firstHour = -1;
588 Boolean isInQuote = false, hasA = false, had12Hour = false, had24Hour = false;
589 for (CFIndex idx = 0; idx < cnt; idx++) {
590 Boolean emit = true;
591 UniChar ch = CFStringGetCharacterAtIndex(inString, idx);
592 switch (ch) {
593 case '\'': isInQuote = !isInQuote; break;
594 case 'h': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had12Hour = true; if (doForce24) ch = 'H';} break; // switch 12-hour to 24-hour
595 case 'K': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had12Hour = true; if (doForce24) ch = 'k';} break; // switch 12-hour to 24-hour
596 case 'H': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had24Hour = true; if (doForce12) ch = 'h';} break; // switch 24-hour to 12-hour
597 case 'k': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had24Hour = true; if (doForce12) ch = 'K';} break; // switch 24-hour to 12-hour
598 case 'm': if (!isInQuote) lastMinute = CFStringGetLength(outString); break;
599 case 's': if (!isInQuote) lastSecond = CFStringGetLength(outString); break;
600 case 'a': if (!isInQuote) hasA = true;
601 if (!isInQuote && doForce24) {
602 // skip 'a' and one optional trailing space
603 emit = false;
604 if (idx + 1 < cnt && ' ' == CFStringGetCharacterAtIndex(inString, idx + 1)) idx++;
605 }
606 break;
607 case ' ':
608 if (!isInQuote && doForce24) {
609 // if next character is 'a' AND we have seen the hour designator, skip space and 'a'
610 if (idx + 1 < cnt && 'a' == CFStringGetCharacterAtIndex(inString, idx + 1) && -1 != firstHour) {
611 emit = false;
612 idx++;
613 }
614 }
615 break;
616 }
617 if (emit) CFStringAppendCharacters(outString, &ch, 1);
618 }
619 if (doForce12 && !hasA && had24Hour) {
620 CFStringRef locName = CFLocaleGetIdentifier(formatter->_locale);
621 if (-1 != firstHour && (CFStringHasPrefix(locName, CFSTR("ko")) || CFEqual(locName, CFSTR("zh_SG")))) {
622 CFStringInsert(outString, firstHour, CFSTR("a "));
623 } else if (-1 != firstHour && (CFStringHasPrefix(locName, CFSTR("zh")) || CFStringHasPrefix(locName, CFSTR("ja")))) {
624 CFStringInsert(outString, firstHour, CFSTR("a"));
625 } else {
626 CFIndex lastPos = (-1 != lastSecond) ? lastSecond : ((-1 != lastMinute) ? lastMinute : -1);
627 if (-1 != lastPos) {
628 cnt = CFStringGetLength(outString);
629 lastPos++;
630 UniChar ch = (lastPos < cnt) ? CFStringGetCharacterAtIndex(outString, lastPos) : 0;
631 switch (ch) {
632 case '\"': lastPos++; break;
633 case '\'':;
634 again:;
635 do {
636 lastPos++;
637 ch = (lastPos < cnt) ? CFStringGetCharacterAtIndex(outString, lastPos) : 0;
638 } while ('\'' != ch && '\0' != ch);
639 if ('\'' == ch) lastPos++;
640 ch = (lastPos < cnt) ? CFStringGetCharacterAtIndex(outString, lastPos) : 0;
641 if ('\'' == ch) goto again;
642 break;
643 }
644 CFStringInsert(outString, lastPos, CFSTR(" a"));
645 }
646 }
647 }
648 return outString;
649 }
650
651 static void __CFDateFormatterCustomize(CFDateFormatterRef formatter) {
652 Boolean wantRelative = (NULL != formatter->_property._DoesRelativeDateFormatting && formatter->_property._DoesRelativeDateFormatting == kCFBooleanTrue);
653 Boolean hasFormat = (NULL != formatter->_property._HasCustomFormat && formatter->_property._HasCustomFormat == kCFBooleanTrue);
654 if (wantRelative && !hasFormat) {
655 __substituteFormatStringFromPrefsDFRelative(formatter);
656 } else {
657 __substituteFormatStringFromPrefsDF(formatter, false);
658 __substituteFormatStringFromPrefsDF(formatter, true);
659 }
660 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
661 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUDateTimeSymbols")) : NULL;
662 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
663 CFDictionaryApplyFunction((CFDictionaryRef)metapref, __CFDateFormatterApplySymbolPrefs, formatter);
664 }
665 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleFirstWeekday")) : NULL;
666 CFStringRef calID = (CFStringRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarIdentifierKey);
667 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
668 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, calID);
669 }
670 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) {
671 CFIndex wkdy;
672 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &wkdy)) {
673 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
674 if (cal) ucal_setAttribute(cal, UCAL_FIRST_DAY_OF_WEEK, wkdy);
675 }
676 }
677 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleMinDaysInFirstWeek")) : NULL;
678 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
679 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, calID);
680 }
681 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) {
682 CFIndex mwd;
683 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &mwd)) {
684 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
685 if (cal) ucal_setAttribute(cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK, mwd);
686 }
687 }
688 }
689
690 CFLocaleRef CFDateFormatterGetLocale(CFDateFormatterRef formatter) {
691 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
692 return formatter->_locale;
693 }
694
695 CFDateFormatterStyle CFDateFormatterGetDateStyle(CFDateFormatterRef formatter) {
696 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
697 return formatter->_dateStyle;
698 }
699
700 CFDateFormatterStyle CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter) {
701 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
702 return formatter->_timeStyle;
703 }
704
705 CFStringRef CFDateFormatterGetFormat(CFDateFormatterRef formatter) {
706 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
707 return formatter->_format;
708 }
709
710 void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatString) {
711 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
712 __CFGenericValidateType(formatString, CFStringGetTypeID());
713 formatString = __CFDateFormatterCreateForcedString(formatter, formatString);
714 CFIndex cnt = CFStringGetLength(formatString);
715 CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__);
716 if (formatter->_format != formatString && cnt <= 1024) {
717 __ResetUDateFormat(formatter, true);
718 STACK_BUFFER_DECL(UChar, ubuffer, cnt);
719 const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString);
720 if (NULL == ustr) {
721 CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer);
722 ustr = ubuffer;
723 }
724 UErrorCode status = U_ZERO_ERROR;
725 // udat_applyPattern(formatter->_df, false, ustr, cnt, &status);
726 udat_applyPattern(formatter->_df, false, ustr, cnt);
727 if (U_SUCCESS(status)) {
728 if (formatter->_format) CFRelease(formatter->_format);
729 formatter->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(formatter), formatString);
730 }
731 }
732 if (formatString) CFRelease(formatString);
733 }
734
735 CFStringRef CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFDateRef date) {
736 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
737 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
738 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
739 __CFGenericValidateType(date, CFDateGetTypeID());
740 return CFDateFormatterCreateStringWithAbsoluteTime(allocator, formatter, CFDateGetAbsoluteTime(date));
741 }
742
743 CFStringRef CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFAbsoluteTime at) {
744 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
745 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
746 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
747 UChar *ustr = NULL, ubuffer[BUFFER_SIZE];
748 UErrorCode status = U_ZERO_ERROR;
749 CFIndex used, cnt = BUFFER_SIZE;
750 UDate ud = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0 + 0.5;
751 used = udat_format(formatter->_df, ud, ubuffer, cnt, NULL, &status);
752 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) {
753 cnt = used + 1;
754 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0);
755 status = U_ZERO_ERROR;
756 used = udat_format(formatter->_df, ud, ustr, cnt, NULL, &status);
757 }
758 CFStringRef string = NULL;
759 if (U_SUCCESS(status)) {
760 string = CFStringCreateWithCharacters(allocator, (const UniChar *)(ustr ? ustr : ubuffer), used);
761 }
762 if (ustr) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ustr);
763 return string;
764 }
765
766 CFDateRef CFDateFormatterCreateDateFromString(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep) {
767 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
768 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
769 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
770 __CFGenericValidateType(string, CFStringGetTypeID());
771 CFAbsoluteTime at;
772 if (CFDateFormatterGetAbsoluteTimeFromString(formatter, string, rangep, &at)) {
773 return CFDateCreate(allocator, at);
774 }
775 return NULL;
776 }
777
778 Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep, CFAbsoluteTime *atp) {
779 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
780 __CFGenericValidateType(string, CFStringGetTypeID());
781 CFRange range = {0, 0};
782 if (rangep) {
783 range = *rangep;
784 } else {
785 range.length = CFStringGetLength(string);
786 }
787 if (1024 < range.length) range.length = 1024;
788 const UChar *ustr = (UChar *)CFStringGetCharactersPtr(string);
789 STACK_BUFFER_DECL(UChar, ubuffer, (NULL == ustr) ? range.length : 1);
790 if (NULL == ustr) {
791 CFStringGetCharacters(string, range, (UniChar *)ubuffer);
792 ustr = ubuffer;
793 } else {
794 ustr += range.location;
795 }
796 UDate udate;
797 int32_t dpos = 0;
798 UErrorCode status = U_ZERO_ERROR;
799 if (formatter->_property._DefaultDate) {
800 CFAbsoluteTime at = CFDateGetAbsoluteTime(formatter->_property._DefaultDate);
801 udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
802 UDateFormat *df2 = udat_clone(formatter->_df, &status);
803 UCalendar *cal2 = (UCalendar *)udat_getCalendar(df2);
804 ucal_setMillis(cal2, udate, &status);
805 udat_parseCalendar(formatter->_df, cal2, ustr, range.length, &dpos, &status);
806 udate = ucal_getMillis(cal2, &status);
807 udat_close(df2);
808 } else {
809 udate = udat_parse(formatter->_df, ustr, range.length, &dpos, &status);
810 }
811 if (rangep) rangep->length = dpos;
812 if (U_FAILURE(status)) {
813 return false;
814 }
815 if (atp) {
816 *atp = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970;
817 }
818 return true;
819 }
820
821 static void __CFDateFormatterSetSymbolsArray(UDateFormat *icudf, int32_t icucode, int index_base, CFTypeRef value) {
822 UErrorCode status = U_ZERO_ERROR;
823 __CFGenericValidateType(value, CFArrayGetTypeID());
824 CFArrayRef array = (CFArrayRef)value;
825 CFIndex idx, cnt = CFArrayGetCount(array);
826 for (idx = 0; idx < cnt; idx++) {
827 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
828 __CFGenericValidateType(item, CFStringGetTypeID());
829 CFIndex item_cnt = CFStringGetLength(item);
830 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
831 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item);
832 if (NULL == item_ustr) {
833 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
834 CFStringGetCharacters(item, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
835 item_ustr = item_buffer;
836 }
837 status = U_ZERO_ERROR;
838 udat_setSymbols(icudf, (UDateFormatSymbolType)icucode, idx + index_base, item_ustr, item_cnt, &status);
839 }
840 }
841
842 static CFArrayRef __CFDateFormatterGetSymbolsArray(UDateFormat *icudf, int32_t icucode, int index_base) {
843 UErrorCode status = U_ZERO_ERROR;
844 CFIndex idx, cnt = udat_countSymbols(icudf, (UDateFormatSymbolType)icucode) - index_base;
845 STACK_BUFFER_DECL(CFStringRef, strings, cnt);
846 for (idx = 0; idx < cnt; idx++) {
847 UChar ubuffer[BUFFER_SIZE];
848 CFStringRef str = NULL;
849 status = U_ZERO_ERROR;
850 CFIndex ucnt = udat_getSymbols(icudf, (UDateFormatSymbolType)icucode, idx + index_base, ubuffer, BUFFER_SIZE, &status);
851 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
852 str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ucnt);
853 }
854 strings[idx] = !str ? (CFStringRef)CFRetain(CFSTR("<error>")) : str;
855 }
856 CFArrayRef array = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)strings, cnt, &kCFTypeArrayCallBacks);
857 while (cnt--) {
858 CFRelease(strings[cnt]);
859 }
860 return array;
861 }
862
863 #define SET_SYMBOLS_ARRAY(A, B, C) \
864 if (!directToICU) { \
865 oldProperty = formatter->_property. C; \
866 formatter->_property. C = NULL; \
867 } \
868 __CFDateFormatterSetSymbolsArray(formatter->_df, A, B, value); \
869 if (!directToICU) { \
870 formatter->_property. C = __CFDateFormatterGetSymbolsArray(formatter->_df, A, B); \
871 }
872
873 static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value, Boolean directToICU) {
874 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
875 __CFGenericValidateType(key, CFStringGetTypeID());
876 CFTypeRef oldProperty = NULL;
877 UErrorCode status = U_ZERO_ERROR;
878 UChar ubuffer[BUFFER_SIZE];
879
880 if (kCFDateFormatterIsLenientKey == key) {
881 if (!directToICU) {
882 oldProperty = formatter->_property. _IsLenient;
883 formatter->_property. _IsLenient = NULL;
884 }
885 __CFGenericValidateType(value, CFBooleanGetTypeID());
886 udat_setLenient(formatter->_df, (kCFBooleanTrue == value));
887 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
888 if (cal) ucal_setAttribute(cal, UCAL_LENIENT, (kCFBooleanTrue == value));
889 if (!directToICU) {
890 formatter->_property. _IsLenient = (CFBooleanRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterIsLenientKey);
891 }
892 } else if (kCFDateFormatterDoesRelativeDateFormattingKey == key) {
893 if (!directToICU) {
894 oldProperty = formatter->_property. _DoesRelativeDateFormatting;
895 formatter->_property. _DoesRelativeDateFormatting = NULL;
896 }
897 __CFGenericValidateType(value, CFBooleanGetTypeID());
898 if (!directToICU) {
899 if (kCFBooleanTrue != value) value = kCFBooleanFalse;
900 formatter->_property. _DoesRelativeDateFormatting = value ? (CFBooleanRef)CFRetain(value) : NULL;
901 __ResetUDateFormat(formatter, false);
902 }
903 } else if (kCFDateFormatterCalendarKey == key) {
904 if (!directToICU) {
905 oldProperty = formatter->_property. _Calendar;
906 formatter->_property. _Calendar = NULL;
907 }
908 __CFGenericValidateType(value, CFCalendarGetTypeID());
909 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
910 CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName);
911 CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components);
912 CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifierKey, CFCalendarGetIdentifier((CFCalendarRef)value));
913 localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents);
914 CFRelease(mcomponents);
915 CFRelease(components);
916 CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName);
917 CFRelease(localeName);
918 CFRelease(formatter->_locale);
919 formatter->_locale = newLocale;
920 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, CFLocaleGetIdentifier(formatter->_locale), formatter->_property._TimeZone);
921 if (cal) ucal_setAttribute(cal, UCAL_FIRST_DAY_OF_WEEK, CFCalendarGetFirstWeekday((CFCalendarRef)value));
922 if (cal) ucal_setAttribute(cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK, CFCalendarGetMinimumDaysInFirstWeek((CFCalendarRef)value));
923 if (cal) udat_setCalendar(formatter->_df, cal);
924 if (cal) ucal_close(cal);
925 if (!directToICU) {
926 formatter->_property. _Calendar = (CFCalendarRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterCalendarKey);
927 }
928 } else if (kCFDateFormatterCalendarIdentifierKey == key) {
929 if (!directToICU) {
930 oldProperty = formatter->_property. _CalendarName;
931 formatter->_property. _CalendarName = NULL;
932 }
933 __CFGenericValidateType(value, CFStringGetTypeID());
934 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
935 CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName);
936 CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components);
937 CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifierKey, value);
938 localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents);
939 CFRelease(mcomponents);
940 CFRelease(components);
941 CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName);
942 CFRelease(localeName);
943 CFRelease(formatter->_locale);
944 formatter->_locale = newLocale;
945 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, CFLocaleGetIdentifier(formatter->_locale), formatter->_property._TimeZone);
946 if (cal) udat_setCalendar(formatter->_df, cal);
947 if (cal) ucal_close(cal);
948 if (!directToICU) {
949 formatter->_property. _CalendarName = (CFStringRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterCalendarIdentifierKey);
950 }
951 } else if (kCFDateFormatterTimeZoneKey == key) {
952 if (formatter->_property. _TimeZone != value) {
953 if (!directToICU) {
954 oldProperty = formatter->_property. _TimeZone;
955 formatter->_property. _TimeZone = NULL;
956 }
957 __CFGenericValidateType(value, CFTimeZoneGetTypeID());
958 CFTimeZoneRef old = formatter->_property._TimeZone;
959 formatter->_property._TimeZone = value ? (CFTimeZoneRef)CFRetain(value) : CFTimeZoneCopyDefault();
960 if (old) CFRelease(old);
961 CFStringRef tznam = CFTimeZoneGetName(formatter->_property._TimeZone);
962 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
963 CFIndex ucnt = CFStringGetLength(tznam);
964 if (BUFFER_SIZE < ucnt) ucnt = BUFFER_SIZE;
965 CFStringGetCharacters(tznam, CFRangeMake(0, ucnt), (UniChar *)ubuffer);
966 ucal_setTimeZone(cal, ubuffer, ucnt, &status);
967 if (!directToICU) {
968 old = formatter->_property._TimeZone;
969 formatter->_property. _TimeZone = (CFTimeZoneRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterTimeZoneKey);
970 if (old) CFRelease(old);
971 }
972 }
973 } else if (kCFDateFormatterDefaultFormatKey == key) {
974 // read-only attribute
975 } else if (kCFDateFormatterTwoDigitStartDateKey == key) {
976 if (!directToICU) {
977 oldProperty = formatter->_property. _TwoDigitStartDate;
978 formatter->_property. _TwoDigitStartDate = NULL;
979 }
980 __CFGenericValidateType(value, CFDateGetTypeID());
981 CFAbsoluteTime at = CFDateGetAbsoluteTime((CFDateRef)value);
982 UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
983 udat_set2DigitYearStart(formatter->_df, udate, &status);
984 if (!directToICU) {
985 formatter->_property. _TwoDigitStartDate = (CFDateRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterTwoDigitStartDateKey);
986 }
987 } else if (kCFDateFormatterDefaultDateKey == key) {
988 if (!directToICU) {
989 oldProperty = formatter->_property. _DefaultDate;
990 formatter->_property. _DefaultDate = NULL;
991 }
992 __CFGenericValidateType(value, CFDateGetTypeID());
993 if (!directToICU) {
994 formatter->_property._DefaultDate = value ? (CFDateRef)CFRetain(value) : NULL;
995 }
996 } else if (kCFDateFormatterGregorianStartDateKey == key) {
997 if (!directToICU) {
998 oldProperty = formatter->_property. _GregorianStartDate;
999 formatter->_property. _GregorianStartDate = NULL;
1000 }
1001 __CFGenericValidateType(value, CFDateGetTypeID());
1002 CFAbsoluteTime at = CFDateGetAbsoluteTime((CFDateRef)value);
1003 UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
1004 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
1005 ucal_setGregorianChange(cal, udate, &status);
1006 if (!directToICU) {
1007 formatter->_property. _GregorianStartDate = (CFDateRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterGregorianStartDateKey);
1008 }
1009 } else if (kCFDateFormatterEraSymbolsKey == key) {
1010 SET_SYMBOLS_ARRAY(UDAT_ERAS, 0, _EraSymbols)
1011 } else if (kCFDateFormatterLongEraSymbolsKey == key) {
1012 SET_SYMBOLS_ARRAY(UDAT_ERA_NAMES, 0, _LongEraSymbols)
1013 } else if (kCFDateFormatterMonthSymbolsKey == key) {
1014 SET_SYMBOLS_ARRAY(UDAT_MONTHS, 0, _MonthSymbols)
1015 } else if (kCFDateFormatterShortMonthSymbolsKey == key) {
1016 SET_SYMBOLS_ARRAY(UDAT_SHORT_MONTHS, 0, _ShortMonthSymbols)
1017 } else if (kCFDateFormatterVeryShortMonthSymbolsKey == key) {
1018 SET_SYMBOLS_ARRAY(UDAT_NARROW_MONTHS, 0, _VeryShortMonthSymbols)
1019 } else if (kCFDateFormatterStandaloneMonthSymbolsKey == key) {
1020 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_MONTHS, 0, _StandaloneMonthSymbols)
1021 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey == key) {
1022 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_MONTHS, 0, _ShortStandaloneMonthSymbols)
1023 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey == key) {
1024 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_MONTHS, 0, _VeryShortStandaloneMonthSymbols)
1025 } else if (kCFDateFormatterWeekdaySymbolsKey == key) {
1026 SET_SYMBOLS_ARRAY(UDAT_WEEKDAYS, 1, _WeekdaySymbols)
1027 } else if (kCFDateFormatterShortWeekdaySymbolsKey == key) {
1028 SET_SYMBOLS_ARRAY(UDAT_SHORT_WEEKDAYS, 1, _ShortWeekdaySymbols)
1029 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey == key) {
1030 SET_SYMBOLS_ARRAY(UDAT_NARROW_WEEKDAYS, 1, _VeryShortWeekdaySymbols)
1031 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey == key) {
1032 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_WEEKDAYS, 1, _StandaloneWeekdaySymbols)
1033 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey == key) {
1034 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_WEEKDAYS, 1, _ShortStandaloneWeekdaySymbols)
1035 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey == key) {
1036 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_WEEKDAYS, 1, _VeryShortStandaloneWeekdaySymbols)
1037 } else if (kCFDateFormatterQuarterSymbolsKey == key) {
1038 SET_SYMBOLS_ARRAY(UDAT_QUARTERS, 0, _QuarterSymbols)
1039 } else if (kCFDateFormatterShortQuarterSymbolsKey == key) {
1040 SET_SYMBOLS_ARRAY(UDAT_SHORT_QUARTERS, 0, _ShortQuarterSymbols)
1041 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey == key) {
1042 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_QUARTERS, 0, _StandaloneQuarterSymbols)
1043 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey == key) {
1044 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_QUARTERS, 0, _ShortStandaloneQuarterSymbols)
1045 } else if (kCFDateFormatterAMSymbolKey == key) {
1046 if (!directToICU) {
1047 oldProperty = formatter->_property. _AMSymbol;
1048 formatter->_property. _AMSymbol = NULL;
1049 }
1050 __CFGenericValidateType(value, CFStringGetTypeID());
1051 CFIndex item_cnt = CFStringGetLength((CFStringRef)value);
1052 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
1053 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value);
1054 if (NULL == item_ustr) {
1055 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
1056 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
1057 item_ustr = item_buffer;
1058 }
1059 udat_setSymbols(formatter->_df, UDAT_AM_PMS, 0, item_ustr, item_cnt, &status);
1060 if (!directToICU) {
1061 formatter->_property. _AMSymbol = (CFStringRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterAMSymbolKey);
1062 }
1063 } else if (kCFDateFormatterPMSymbolKey == key) {
1064 if (!directToICU) {
1065 oldProperty = formatter->_property. _PMSymbol;
1066 formatter->_property. _PMSymbol = NULL;
1067 }
1068 __CFGenericValidateType(value, CFStringGetTypeID());
1069 CFIndex item_cnt = CFStringGetLength((CFStringRef)value);
1070 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
1071 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value);
1072 if (NULL == item_ustr) {
1073 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
1074 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
1075 item_ustr = item_buffer;
1076 }
1077 udat_setSymbols(formatter->_df, UDAT_AM_PMS, 1, item_ustr, item_cnt, &status);
1078 if (!directToICU) {
1079 formatter->_property. _PMSymbol = (CFStringRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterPMSymbolKey);
1080 }
1081 } else {
1082 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
1083 }
1084 if (oldProperty) CFRelease(oldProperty);
1085 }
1086
1087 void CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value) {
1088 __CFDateFormatterSetProperty(formatter, key, value, false);
1089 }
1090
1091 CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef key) {
1092 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
1093 __CFGenericValidateType(key, CFStringGetTypeID());
1094 UErrorCode status = U_ZERO_ERROR;
1095 UChar ubuffer[BUFFER_SIZE];
1096
1097 if (kCFDateFormatterIsLenientKey == key) {
1098 if (formatter->_property._IsLenient) return CFRetain(formatter->_property._IsLenient);
1099 return CFRetain(udat_isLenient(formatter->_df) ? kCFBooleanTrue : kCFBooleanFalse);
1100 } else if (kCFDateFormatterDoesRelativeDateFormattingKey == key) {
1101 if (formatter->_property._DoesRelativeDateFormatting) return CFRetain(formatter->_property._DoesRelativeDateFormatting);
1102 return CFRetain(kCFBooleanFalse);
1103 } else if (kCFDateFormatterCalendarKey == key) {
1104 if (formatter->_property._Calendar) return CFRetain(formatter->_property._Calendar);
1105 CFCalendarRef calendar = (CFCalendarRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarKey);
1106 return calendar ? CFRetain(calendar) : NULL;
1107 } else if (kCFDateFormatterCalendarIdentifierKey == key) {
1108 if (formatter->_property._CalendarName) return CFRetain(formatter->_property._CalendarName);
1109 CFStringRef ident = (CFStringRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarIdentifierKey);
1110 return ident ? CFRetain(ident) : NULL;
1111 } else if (kCFDateFormatterTimeZoneKey == key) {
1112 if (formatter->_property._TwoDigitStartDate) return CFRetain(formatter->_property._TwoDigitStartDate);
1113 return CFRetain(formatter->_property._TimeZone);
1114 } else if (kCFDateFormatterDefaultFormatKey == key) {
1115 return formatter->_defformat ? CFRetain(formatter->_defformat) : NULL;
1116 } else if (kCFDateFormatterTwoDigitStartDateKey == key) {
1117 if (formatter->_property._TwoDigitStartDate) return CFRetain(formatter->_property._TwoDigitStartDate);
1118 UDate udate = udat_get2DigitYearStart(formatter->_df, &status);
1119 if (U_SUCCESS(status)) {
1120 CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970;
1121 return CFDateCreate(CFGetAllocator(formatter), at);
1122 }
1123 } else if (kCFDateFormatterDefaultDateKey == key) {
1124 return formatter->_property._DefaultDate ? CFRetain(formatter->_property._DefaultDate) : NULL;
1125 } else if (kCFDateFormatterGregorianStartDateKey == key) {
1126 if (formatter->_property._GregorianStartDate) return CFRetain(formatter->_property._GregorianStartDate);
1127 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
1128 UDate udate = ucal_getGregorianChange(cal, &status);
1129 if (U_SUCCESS(status)) {
1130 CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970;
1131 return CFDateCreate(CFGetAllocator(formatter), at);
1132 }
1133 } else if (kCFDateFormatterEraSymbolsKey == key) {
1134 if (formatter->_property._EraSymbols) return CFRetain(formatter->_property._EraSymbols);
1135 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_ERAS, 0);
1136 } else if (kCFDateFormatterLongEraSymbolsKey == key) {
1137 if (formatter->_property._LongEraSymbols) return CFRetain(formatter->_property._LongEraSymbols);
1138 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_ERA_NAMES, 0);
1139 } else if (kCFDateFormatterMonthSymbolsKey == key) {
1140 if (formatter->_property._MonthSymbols) return CFRetain(formatter->_property._MonthSymbols);
1141 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_MONTHS, 0);
1142 } else if (kCFDateFormatterShortMonthSymbolsKey == key) {
1143 if (formatter->_property._ShortMonthSymbols) return CFRetain(formatter->_property._ShortMonthSymbols);
1144 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_SHORT_MONTHS, 0);
1145 } else if (kCFDateFormatterVeryShortMonthSymbolsKey == key) {
1146 if (formatter->_property._VeryShortMonthSymbols) return CFRetain(formatter->_property._VeryShortMonthSymbols);
1147 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_NARROW_MONTHS, 0);
1148 } else if (kCFDateFormatterStandaloneMonthSymbolsKey == key) {
1149 if (formatter->_property._StandaloneMonthSymbols) return CFRetain(formatter->_property._StandaloneMonthSymbols);
1150 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_MONTHS, 0);
1151 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey == key) {
1152 if (formatter->_property._ShortStandaloneMonthSymbols) return CFRetain(formatter->_property._ShortStandaloneMonthSymbols);
1153 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_SHORT_MONTHS, 0);
1154 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey == key) {
1155 if (formatter->_property._VeryShortStandaloneMonthSymbols) return CFRetain(formatter->_property._VeryShortStandaloneMonthSymbols);
1156 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_NARROW_MONTHS, 0);
1157 } else if (kCFDateFormatterWeekdaySymbolsKey == key) {
1158 if (formatter->_property._WeekdaySymbols) return CFRetain(formatter->_property._WeekdaySymbols);
1159 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_WEEKDAYS, 1);
1160 } else if (kCFDateFormatterShortWeekdaySymbolsKey == key) {
1161 if (formatter->_property._ShortWeekdaySymbols) return CFRetain(formatter->_property._ShortWeekdaySymbols);
1162 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_SHORT_WEEKDAYS, 1);
1163 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey == key) {
1164 if (formatter->_property._VeryShortWeekdaySymbols) return CFRetain(formatter->_property._VeryShortWeekdaySymbols);
1165 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_NARROW_WEEKDAYS, 1);
1166 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey == key) {
1167 if (formatter->_property._StandaloneWeekdaySymbols) return CFRetain(formatter->_property._StandaloneWeekdaySymbols);
1168 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_WEEKDAYS, 1);
1169 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey == key) {
1170 if (formatter->_property._ShortStandaloneWeekdaySymbols) return CFRetain(formatter->_property._ShortStandaloneWeekdaySymbols);
1171 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_SHORT_WEEKDAYS, 1);
1172 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey == key) {
1173 if (formatter->_property._VeryShortStandaloneWeekdaySymbols) return CFRetain(formatter->_property._VeryShortStandaloneWeekdaySymbols);
1174 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_NARROW_WEEKDAYS, 1);
1175 } else if (kCFDateFormatterQuarterSymbolsKey == key) {
1176 if (formatter->_property._QuarterSymbols) return CFRetain(formatter->_property._QuarterSymbols);
1177 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_QUARTERS, 0);
1178 } else if (kCFDateFormatterShortQuarterSymbolsKey == key) {
1179 if (formatter->_property._ShortQuarterSymbols) return CFRetain(formatter->_property._ShortQuarterSymbols);
1180 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_SHORT_QUARTERS, 0);
1181 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey == key) {
1182 if (formatter->_property._StandaloneQuarterSymbols) return CFRetain(formatter->_property._StandaloneQuarterSymbols);
1183 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_QUARTERS, 0);
1184 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey == key) {
1185 if (formatter->_property._ShortStandaloneQuarterSymbols) return CFRetain(formatter->_property._ShortStandaloneQuarterSymbols);
1186 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_SHORT_QUARTERS, 0);
1187 } else if (kCFDateFormatterAMSymbolKey == key) {
1188 if (formatter->_property._AMSymbol) return CFRetain(formatter->_property._AMSymbol);
1189 CFIndex cnt = udat_countSymbols(formatter->_df, UDAT_AM_PMS);
1190 if (2 <= cnt) {
1191 CFIndex ucnt = udat_getSymbols(formatter->_df, UDAT_AM_PMS, 0, ubuffer, BUFFER_SIZE, &status);
1192 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1193 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt);
1194 }
1195 }
1196 } else if (kCFDateFormatterPMSymbolKey == key) {
1197 if (formatter->_property._PMSymbol) return CFRetain(formatter->_property._PMSymbol);
1198 CFIndex cnt = udat_countSymbols(formatter->_df, UDAT_AM_PMS);
1199 if (2 <= cnt) {
1200 CFIndex ucnt = udat_getSymbols(formatter->_df, UDAT_AM_PMS, 1, ubuffer, BUFFER_SIZE, &status);
1201 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1202 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt);
1203 }
1204 }
1205 } else {
1206 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
1207 }
1208 return NULL;
1209 }
1210
1211