2 * Copyright (c) 2013 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 2002-2013, Apple Inc. All rights reserved.
26 Responsibility: David Smith
29 #define U_SHOW_INTERNAL_API 1
31 #include <CoreFoundation/CFDateFormatter.h>
32 #include <CoreFoundation/CFDate.h>
33 #include <CoreFoundation/CFTimeZone.h>
34 #include <CoreFoundation/CFCalendar.h>
35 #include <CoreFoundation/CFNumber.h>
37 #include "CFInternal.h"
38 #include "CFLocaleInternal.h"
39 #include "CFICULogging.h"
44 typedef CF_ENUM(CFIndex
, CFDateFormatterAmbiguousYearHandling
) {
45 kCFDateFormatterAmbiguousYearFailToParse
= 0, // fail the parse; the default formatter behavior
46 kCFDateFormatterAmbiguousYearAssumeToNone
= 1, // default to assuming era 1, or the year 0-99
47 kCFDateFormatterAmbiguousYearAssumeToCurrent
= 2, // default to assuming the current century or era
48 kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate
= 3,
49 kCFDateFormatterAmbiguousYearAssumeToFuture
= 4,
50 kCFDateFormatterAmbiguousYearAssumeToPast
= 5,
51 kCFDateFormatterAmbiguousYearAssumeToLikelyFuture
= 6,
52 kCFDateFormatterAmbiguousYearAssumeToLikelyPast
= 7
55 extern UCalendar
*__CFCalendarCreateUCalendar(CFStringRef calendarID
, CFStringRef localeID
, CFTimeZoneRef tz
);
57 CF_EXPORT
const CFStringRef kCFDateFormatterCalendarIdentifierKey
;
59 #undef CFReleaseIfNotNull
60 #define CFReleaseIfNotNull(X) if (X) CFRelease(X)
62 #define BUFFER_SIZE 768
64 static CFStringRef
__CFDateFormatterCreateForcedTemplate(CFLocaleRef locale
, CFStringRef inString
);
66 // If you pass in a string in tmplate, you get back NULL (failure) or a CFStringRef.
67 // If you pass in an array in tmplate, you get back NULL (global failure) or a CFArrayRef with CFStringRefs or kCFNulls (per-template failure) at each corresponding index.
69 CFArrayRef
CFDateFormatterCreateDateFormatsFromTemplates(CFAllocatorRef allocator
, CFArrayRef tmplates
, CFOptionFlags options
, CFLocaleRef locale
) {
70 return (CFArrayRef
)CFDateFormatterCreateDateFormatFromTemplate(allocator
, (CFStringRef
)tmplates
, options
, locale
);
73 static Boolean
useTemplatePatternGenerator(const char *localeName
, void(^work
)(UDateTimePatternGenerator
*ptg
)) {
74 static UDateTimePatternGenerator
*ptg
;
75 static pthread_mutex_t ptgLock
= PTHREAD_MUTEX_INITIALIZER
;
76 static const char *ptgLocaleName
;
78 static void (^flushCache
)() = ^{
79 __cficu_udatpg_close(ptg
);
81 free((void *)ptgLocaleName
);
84 pthread_mutex_lock(&ptgLock
);
85 if (ptgLocaleName
&& strcmp(ptgLocaleName
, localeName
) != 0) {
88 UErrorCode status
= U_ZERO_ERROR
;
90 ptg
= __cficu_udatpg_open(localeName
, &status
);
91 if (ptg
&& !U_FAILURE(status
)) {
92 ptgLocaleName
= strdup(localeName
);
95 Boolean result
= (NULL
!= ptg
&& !U_FAILURE(status
));
99 pthread_mutex_unlock(&ptgLock
);
104 CFStringRef
CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator
, CFStringRef tmplate
, CFOptionFlags options
, CFLocaleRef locale
) {
105 if (allocator
) __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
106 if (locale
) __CFGenericValidateType(locale
, CFLocaleGetTypeID());
107 Boolean tmplateIsString
= (CFStringGetTypeID() == CFGetTypeID(tmplate
));
108 if (!tmplateIsString
) {
109 __CFGenericValidateType(tmplate
, CFArrayGetTypeID());
112 CFStringRef localeName
= locale
? CFLocaleGetIdentifier(locale
) : CFSTR("");
113 char buffer
[BUFFER_SIZE
];
114 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
116 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
122 __block CFTypeRef result
= tmplateIsString
? NULL
: (CFTypeRef
)CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
124 Boolean success
= useTemplatePatternGenerator(cstr
, ^(UDateTimePatternGenerator
*ptg
) {
127 for (CFIndex idx
= 0, cnt
= tmplateIsString
? 1 : CFArrayGetCount((CFArrayRef
)tmplate
); idx
< cnt
; idx
++) {
128 CFStringRef tmplateString
= tmplateIsString
? (CFStringRef
)tmplate
: (CFStringRef
)CFArrayGetValueAtIndex((CFArrayRef
)tmplate
, idx
);
129 CFStringRef resultString
= NULL
;
131 tmplateString
= __CFDateFormatterCreateForcedTemplate(locale
? locale
: CFLocaleGetSystem(), tmplateString
);
133 CFIndex jCount
= 0; // the only interesting cases are 0, 1, and 2 (adjacent)
134 CFRange r
= CFStringFind(tmplateString
, CFSTR("j"), 0);
135 if (kCFNotFound
!= r
.location
) {
137 if ((r
.location
+ 1 < CFStringGetLength(tmplateString
)) && ('j' == CFStringGetCharacterAtIndex(tmplateString
, r
.location
+ 1))) {
142 UChar pattern
[BUFFER_SIZE
], skel
[BUFFER_SIZE
], bpat
[BUFFER_SIZE
];
143 CFIndex tmpltLen
= CFStringGetLength(tmplateString
);
144 if (BUFFER_SIZE
< tmpltLen
) tmpltLen
= BUFFER_SIZE
;
145 CFStringGetCharacters(tmplateString
, CFRangeMake(0, tmpltLen
), (UniChar
*)pattern
);
146 CFRelease(tmplateString
);
148 int32_t patlen
= tmpltLen
;
149 UErrorCode status
= U_ZERO_ERROR
;
150 int32_t skellen
= __cficu_udatpg_getSkeleton(ptg
, pattern
, patlen
, skel
, sizeof(skel
) / sizeof(skel
[0]), &status
);
151 if (!U_FAILURE(status
)) {
152 if ((0 < jCount
) && (skellen
+ jCount
< (sizeof(skel
) / sizeof(skel
[0])))) {
153 skel
[skellen
++] = 'j';
154 if (1 < jCount
) skel
[skellen
++] = 'j';
157 status
= U_ZERO_ERROR
;
158 int32_t bpatlen
= __cficu_udatpg_getBestPattern(ptg
, skel
, skellen
, bpat
, sizeof(bpat
) / sizeof(bpat
[0]), &status
);
159 if (!U_FAILURE(status
)) {
160 resultString
= CFStringCreateWithCharacters(allocator
, (const UniChar
*)bpat
, bpatlen
);
164 if (tmplateIsString
) {
165 result
= (CFTypeRef
)resultString
;
167 CFArrayAppendValue((CFMutableArrayRef
)result
, resultString
? (CFTypeRef
)resultString
: (CFTypeRef
)kCFNull
);
168 if (resultString
) CFRelease(resultString
);
178 return (CFStringRef
)result
;
181 struct __CFDateFormatter
{
185 CFDateFormatterStyle _timeStyle
;
186 CFDateFormatterStyle _dateStyle
;
188 CFStringRef _defformat
;
190 CFBooleanRef _IsLenient
;
191 CFBooleanRef _DoesRelativeDateFormatting
;
192 CFBooleanRef _HasCustomFormat
;
193 CFTimeZoneRef _TimeZone
;
194 CFCalendarRef _Calendar
;
195 CFStringRef _CalendarName
;
196 CFDateRef _TwoDigitStartDate
;
197 CFDateRef _DefaultDate
;
198 CFDateRef _GregorianStartDate
;
199 CFArrayRef _EraSymbols
;
200 CFArrayRef _LongEraSymbols
;
201 CFArrayRef _MonthSymbols
;
202 CFArrayRef _ShortMonthSymbols
;
203 CFArrayRef _VeryShortMonthSymbols
;
204 CFArrayRef _StandaloneMonthSymbols
;
205 CFArrayRef _ShortStandaloneMonthSymbols
;
206 CFArrayRef _VeryShortStandaloneMonthSymbols
;
207 CFArrayRef _WeekdaySymbols
;
208 CFArrayRef _ShortWeekdaySymbols
;
209 CFArrayRef _VeryShortWeekdaySymbols
;
210 CFArrayRef _StandaloneWeekdaySymbols
;
211 CFArrayRef _ShortStandaloneWeekdaySymbols
;
212 CFArrayRef _VeryShortStandaloneWeekdaySymbols
;
213 CFArrayRef _QuarterSymbols
;
214 CFArrayRef _ShortQuarterSymbols
;
215 CFArrayRef _StandaloneQuarterSymbols
;
216 CFArrayRef _ShortStandaloneQuarterSymbols
;
217 CFStringRef _AMSymbol
;
218 CFStringRef _PMSymbol
;
219 CFNumberRef _AmbiguousYearStrategy
;
220 CFBooleanRef _UsesCharacterDirection
;
222 // the following are from preferences
223 CFArrayRef _CustomEraSymbols
;
224 CFArrayRef _CustomLongEraSymbols
;
225 CFArrayRef _CustomMonthSymbols
;
226 CFArrayRef _CustomShortMonthSymbols
;
227 CFArrayRef _CustomVeryShortMonthSymbols
;
228 CFArrayRef _CustomStandaloneMonthSymbols
;
229 CFArrayRef _CustomShortStandaloneMonthSymbols
;
230 CFArrayRef _CustomVeryShortStandaloneMonthSymbols
;
231 CFArrayRef _CustomWeekdaySymbols
;
232 CFArrayRef _CustomShortWeekdaySymbols
;
233 CFArrayRef _CustomVeryShortWeekdaySymbols
;
234 CFArrayRef _CustomStandaloneWeekdaySymbols
;
235 CFArrayRef _CustomShortStandaloneWeekdaySymbols
;
236 CFArrayRef _CustomVeryShortStandaloneWeekdaySymbols
;
237 CFArrayRef _CustomQuarterSymbols
;
238 CFArrayRef _CustomShortQuarterSymbols
;
239 CFArrayRef _CustomStandaloneQuarterSymbols
;
240 CFArrayRef _CustomShortStandaloneQuarterSymbols
;
241 CFStringRef _CustomDateFormat
;
242 CFStringRef _CustomTimeFormat
;
243 CFBooleanRef _Custom24Hour
;
244 CFBooleanRef _Custom12Hour
;
245 CFStringRef _CustomAMSymbol
;
246 CFStringRef _CustomPMSymbol
;
247 CFDictionaryRef _CustomFirstWeekday
;
248 CFDictionaryRef _CustomMinDaysInFirstWeek
;
253 static CFStringRef
__CFDateFormatterCopyDescription(CFTypeRef cf
) {
254 CFDateFormatterRef formatter
= (CFDateFormatterRef
)cf
;
255 return CFStringCreateWithFormat(CFGetAllocator(formatter
), NULL
, CFSTR("<CFDateFormatter %p [%p]>"), cf
, CFGetAllocator(formatter
));
258 static void __CFDateFormatterDeallocate(CFTypeRef cf
) {
259 CFDateFormatterRef formatter
= (CFDateFormatterRef
)cf
;
260 if (formatter
->_df
) __cficu_udat_close(formatter
->_df
);
261 if (formatter
->_locale
) CFRelease(formatter
->_locale
);
262 if (formatter
->_format
) CFRelease(formatter
->_format
);
263 if (formatter
->_defformat
) CFRelease(formatter
->_defformat
);
264 CFReleaseIfNotNull(formatter
->_property
._IsLenient
);
265 CFReleaseIfNotNull(formatter
->_property
._DoesRelativeDateFormatting
);
266 CFReleaseIfNotNull(formatter
->_property
._TimeZone
);
267 CFReleaseIfNotNull(formatter
->_property
._Calendar
);
268 CFReleaseIfNotNull(formatter
->_property
._CalendarName
);
269 CFReleaseIfNotNull(formatter
->_property
._TwoDigitStartDate
);
270 CFReleaseIfNotNull(formatter
->_property
._DefaultDate
);
271 CFReleaseIfNotNull(formatter
->_property
._GregorianStartDate
);
272 CFReleaseIfNotNull(formatter
->_property
._EraSymbols
);
273 CFReleaseIfNotNull(formatter
->_property
._LongEraSymbols
);
274 CFReleaseIfNotNull(formatter
->_property
._MonthSymbols
);
275 CFReleaseIfNotNull(formatter
->_property
._ShortMonthSymbols
);
276 CFReleaseIfNotNull(formatter
->_property
._VeryShortMonthSymbols
);
277 CFReleaseIfNotNull(formatter
->_property
._StandaloneMonthSymbols
);
278 CFReleaseIfNotNull(formatter
->_property
._ShortStandaloneMonthSymbols
);
279 CFReleaseIfNotNull(formatter
->_property
._VeryShortStandaloneMonthSymbols
);
280 CFReleaseIfNotNull(formatter
->_property
._WeekdaySymbols
);
281 CFReleaseIfNotNull(formatter
->_property
._ShortWeekdaySymbols
);
282 CFReleaseIfNotNull(formatter
->_property
._VeryShortWeekdaySymbols
);
283 CFReleaseIfNotNull(formatter
->_property
._StandaloneWeekdaySymbols
);
284 CFReleaseIfNotNull(formatter
->_property
._ShortStandaloneWeekdaySymbols
);
285 CFReleaseIfNotNull(formatter
->_property
._VeryShortStandaloneWeekdaySymbols
);
286 CFReleaseIfNotNull(formatter
->_property
._QuarterSymbols
);
287 CFReleaseIfNotNull(formatter
->_property
._ShortQuarterSymbols
);
288 CFReleaseIfNotNull(formatter
->_property
._StandaloneQuarterSymbols
);
289 CFReleaseIfNotNull(formatter
->_property
._ShortStandaloneQuarterSymbols
);
290 CFReleaseIfNotNull(formatter
->_property
._AMSymbol
);
291 CFReleaseIfNotNull(formatter
->_property
._PMSymbol
);
292 CFReleaseIfNotNull(formatter
->_property
._AmbiguousYearStrategy
);
293 CFReleaseIfNotNull(formatter
->_property
._UsesCharacterDirection
);
294 CFReleaseIfNotNull(formatter
->_property
._CustomEraSymbols
);
295 CFReleaseIfNotNull(formatter
->_property
._CustomMonthSymbols
);
296 CFReleaseIfNotNull(formatter
->_property
._CustomShortMonthSymbols
);
297 CFReleaseIfNotNull(formatter
->_property
._CustomWeekdaySymbols
);
298 CFReleaseIfNotNull(formatter
->_property
._CustomShortWeekdaySymbols
);
299 CFReleaseIfNotNull(formatter
->_property
._CustomLongEraSymbols
);
300 CFReleaseIfNotNull(formatter
->_property
._CustomVeryShortMonthSymbols
);
301 CFReleaseIfNotNull(formatter
->_property
._CustomVeryShortWeekdaySymbols
);
302 CFReleaseIfNotNull(formatter
->_property
._CustomStandaloneMonthSymbols
);
303 CFReleaseIfNotNull(formatter
->_property
._CustomShortStandaloneMonthSymbols
);
304 CFReleaseIfNotNull(formatter
->_property
._CustomVeryShortStandaloneMonthSymbols
);
305 CFReleaseIfNotNull(formatter
->_property
._CustomStandaloneWeekdaySymbols
);
306 CFReleaseIfNotNull(formatter
->_property
._CustomShortStandaloneWeekdaySymbols
);
307 CFReleaseIfNotNull(formatter
->_property
._CustomVeryShortStandaloneWeekdaySymbols
);
308 CFReleaseIfNotNull(formatter
->_property
._CustomQuarterSymbols
);
309 CFReleaseIfNotNull(formatter
->_property
._CustomShortQuarterSymbols
);
310 CFReleaseIfNotNull(formatter
->_property
._CustomShortStandaloneQuarterSymbols
);
311 CFReleaseIfNotNull(formatter
->_property
._CustomDateFormat
);
312 CFReleaseIfNotNull(formatter
->_property
._CustomTimeFormat
);
313 CFReleaseIfNotNull(formatter
->_property
._Custom24Hour
);
314 CFReleaseIfNotNull(formatter
->_property
._Custom12Hour
);
315 CFReleaseIfNotNull(formatter
->_property
._CustomAMSymbol
);
316 CFReleaseIfNotNull(formatter
->_property
._CustomPMSymbol
);
317 CFReleaseIfNotNull(formatter
->_property
._CustomFirstWeekday
);
318 CFReleaseIfNotNull(formatter
->_property
._CustomMinDaysInFirstWeek
);
321 static CFStringRef
__CFDateFormatterCreateForcedString(CFDateFormatterRef formatter
, CFStringRef inString
);
323 static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter
, CFStringRef key
, CFTypeRef value
, Boolean directToICU
);
324 static void __CFDateFormatterStoreSymbolPrefs(const void *key
, const void *value
, void *context
);
325 extern CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
);
326 static void __substituteFormatStringFromPrefsDFRelative(CFDateFormatterRef formatter
);
327 static void __substituteFormatStringFromPrefsDF(CFDateFormatterRef formatter
, bool doTime
);
328 static void __CFDateFormatterSetSymbolsArray(UDateFormat
*icudf
, int32_t icucode
, int index_base
, CFTypeRef value
);
330 static void __ReadCustomUDateFormatProperty(CFDateFormatterRef formatter
) {
331 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
332 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUDateTimeSymbols")) : NULL
;
333 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
334 CFDictionaryApplyFunction((CFDictionaryRef
)metapref
, __CFDateFormatterStoreSymbolPrefs
, formatter
);
336 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleFirstWeekday")) : NULL
;
337 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
338 formatter
->_property
._CustomFirstWeekday
= (CFDictionaryRef
)CFRetain(metapref
);
340 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleMinDaysInFirstWeek")) : NULL
;
341 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
342 formatter
->_property
._CustomMinDaysInFirstWeek
= (CFDictionaryRef
)CFRetain(metapref
);
344 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUForce24HourTime")) : NULL
;
345 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFBooleanGetTypeID()) {
346 formatter
->_property
._Custom24Hour
= (CFBooleanRef
)CFRetain(metapref
);
348 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUForce12HourTime")) : NULL
;
349 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFBooleanGetTypeID()) {
350 formatter
->_property
._Custom12Hour
= (CFBooleanRef
)CFRetain(metapref
);
352 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUDateFormatStrings")) : NULL
;
353 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
355 switch (formatter
->_dateStyle
) {
356 case kCFDateFormatterShortStyle
: key
= CFSTR("1"); break;
357 case kCFDateFormatterMediumStyle
: key
= CFSTR("2"); break;
358 case kCFDateFormatterLongStyle
: key
= CFSTR("3"); break;
359 case kCFDateFormatterFullStyle
: key
= CFSTR("4"); break;
360 default: key
= CFSTR("0"); break;
362 CFStringRef dateFormat
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
363 if (NULL
!= dateFormat
&& CFGetTypeID(dateFormat
) == CFStringGetTypeID()) {
364 formatter
->_property
._CustomDateFormat
= (CFStringRef
)CFRetain(dateFormat
);
367 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUTimeFormatStrings")) : NULL
;
368 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
370 switch (formatter
->_timeStyle
) {
371 case kCFDateFormatterShortStyle
: key
= CFSTR("1"); break;
372 case kCFDateFormatterMediumStyle
: key
= CFSTR("2"); break;
373 case kCFDateFormatterLongStyle
: key
= CFSTR("3"); break;
374 case kCFDateFormatterFullStyle
: key
= CFSTR("4"); break;
375 default: key
= CFSTR("0"); break;
377 CFStringRef timeFormat
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
378 if (NULL
!= timeFormat
&& CFGetTypeID(timeFormat
) == CFStringGetTypeID()) {
379 formatter
->_property
._CustomTimeFormat
= (CFStringRef
)CFRetain(timeFormat
);
384 static void __ApplyUDateFormatSymbol(CFDateFormatterRef formatter
) {
385 UDateFormatSymbolType types
[18] = {UDAT_ERAS
,
390 UDAT_STANDALONE_MONTHS
,
391 UDAT_STANDALONE_SHORT_MONTHS
,
392 UDAT_STANDALONE_NARROW_MONTHS
,
395 UDAT_NARROW_WEEKDAYS
,
396 UDAT_STANDALONE_WEEKDAYS
,
397 UDAT_STANDALONE_SHORT_WEEKDAYS
,
398 UDAT_STANDALONE_NARROW_WEEKDAYS
,
401 UDAT_STANDALONE_QUARTERS
,
402 UDAT_STANDALONE_SHORT_QUARTERS
};
403 int offsets
[18] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0};
404 CFArrayRef symbols
[18] = {formatter
->_property
._EraSymbols
,
405 formatter
->_property
._LongEraSymbols
,
406 formatter
->_property
._MonthSymbols
,
407 formatter
->_property
._ShortMonthSymbols
,
408 formatter
->_property
._VeryShortMonthSymbols
,
409 formatter
->_property
._StandaloneMonthSymbols
,
410 formatter
->_property
._ShortStandaloneMonthSymbols
,
411 formatter
->_property
._VeryShortStandaloneMonthSymbols
,
412 formatter
->_property
._WeekdaySymbols
,
413 formatter
->_property
._ShortWeekdaySymbols
,
414 formatter
->_property
._VeryShortWeekdaySymbols
,
415 formatter
->_property
._StandaloneWeekdaySymbols
,
416 formatter
->_property
._ShortStandaloneWeekdaySymbols
,
417 formatter
->_property
._VeryShortStandaloneWeekdaySymbols
,
418 formatter
->_property
._QuarterSymbols
,
419 formatter
->_property
._ShortQuarterSymbols
,
420 formatter
->_property
._StandaloneQuarterSymbols
,
421 formatter
->_property
._ShortStandaloneQuarterSymbols
423 CFArrayRef customSymbols
[18] = {formatter
->_property
._CustomEraSymbols
,
424 formatter
->_property
._CustomLongEraSymbols
,
425 formatter
->_property
._CustomMonthSymbols
,
426 formatter
->_property
._CustomShortMonthSymbols
,
427 formatter
->_property
._CustomVeryShortMonthSymbols
,
428 formatter
->_property
._CustomStandaloneMonthSymbols
,
429 formatter
->_property
._CustomShortStandaloneMonthSymbols
,
430 formatter
->_property
._CustomVeryShortStandaloneMonthSymbols
,
431 formatter
->_property
._CustomWeekdaySymbols
,
432 formatter
->_property
._CustomShortWeekdaySymbols
,
433 formatter
->_property
._CustomVeryShortWeekdaySymbols
,
434 formatter
->_property
._CustomStandaloneWeekdaySymbols
,
435 formatter
->_property
._CustomShortStandaloneWeekdaySymbols
,
436 formatter
->_property
._CustomVeryShortStandaloneWeekdaySymbols
,
437 formatter
->_property
._CustomQuarterSymbols
,
438 formatter
->_property
._CustomShortQuarterSymbols
,
439 formatter
->_property
._CustomStandaloneQuarterSymbols
,
440 formatter
->_property
._CustomShortStandaloneQuarterSymbols
443 for (CFIndex i
= 0; i
< 18; i
++) {
444 if (symbols
[i
] != NULL
) {
445 __CFDateFormatterSetSymbolsArray(formatter
->_df
, types
[i
], offsets
[i
], symbols
[i
]);
446 } else if (customSymbols
[i
] != NULL
) {
447 __CFDateFormatterSetSymbolsArray(formatter
->_df
, types
[i
], offsets
[i
], customSymbols
[i
]);
455 if (formatter
->_property
._AMSymbol
!= NULL
) {
456 ampm
[0] = formatter
->_property
._AMSymbol
;
457 } else if (formatter
->_property
._CustomAMSymbol
!= NULL
) {
458 ampm
[0] = formatter
->_property
._CustomAMSymbol
;
460 if (formatter
->_property
._PMSymbol
!= NULL
) {
461 ampm
[1] = formatter
->_property
._PMSymbol
;
462 } else if (formatter
->_property
._CustomPMSymbol
!= NULL
) {
463 ampm
[1] = formatter
->_property
._CustomPMSymbol
;
465 for (CFIndex i
= 0; i
< 2; i
++) {
466 CFStringRef sym
= ampm
[i
];
468 CFIndex item_cnt
= CFStringGetLength(sym
);
469 STACK_BUFFER_DECL(UChar
, item_buffer
, __CFMin(BUFFER_SIZE
, item_cnt
));
470 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr(sym
);
471 if (NULL
== item_ustr
) {
472 item_cnt
= __CFMin(BUFFER_SIZE
, item_cnt
);
473 CFStringGetCharacters(sym
, CFRangeMake(0, item_cnt
), (UniChar
*)item_buffer
);
474 item_ustr
= item_buffer
;
476 UErrorCode status
= U_ZERO_ERROR
;
477 __cficu_udat_setSymbols(formatter
->_df
, UDAT_AM_PMS
, i
, item_ustr
, item_cnt
, &status
);
482 static void __SetCalendarProperties(CFDateFormatterRef df
) {
483 CFStringRef calName
= df
->_property
._CalendarName
? (df
->_property
._CalendarName
) : NULL
;
485 calName
= (CFStringRef
)CFLocaleGetValue(df
->_locale
, kCFLocaleCalendarIdentifierKey
);
487 UErrorCode status
= U_ZERO_ERROR
;
488 const UCalendar
*cal
= __cficu_udat_getCalendar(df
->_df
);
489 UCalendar
*new_cal
= NULL
;
491 if (df
->_property
._Calendar
!= NULL
|| df
->_property
._CalendarName
!= NULL
) {
492 UCalendar
*caltmp
= __CFCalendarCreateUCalendar(NULL
, CFLocaleGetIdentifier(df
->_locale
), df
->_property
._TimeZone
);
497 if (new_cal
== NULL
) {
498 new_cal
= __cficu_ucal_clone(cal
, &status
);
501 if (df
->_property
._IsLenient
!= NULL
) {
502 status
= U_ZERO_ERROR
;
503 CFBooleanRef value
= df
->_property
._IsLenient
;
504 __cficu_ucal_setAttribute(new_cal
, UCAL_LENIENT
, (kCFBooleanTrue
== value
));
506 if (df
->_property
._TimeZone
!= NULL
) {
507 status
= U_ZERO_ERROR
;
508 UChar ubuffer
[BUFFER_SIZE
];
509 CFStringRef tznam
= CFTimeZoneGetName(df
->_property
._TimeZone
);
510 CFIndex ucnt
= CFStringGetLength(tznam
);
511 if (BUFFER_SIZE
< ucnt
) ucnt
= BUFFER_SIZE
;
512 CFStringGetCharacters(tznam
, CFRangeMake(0, ucnt
), (UniChar
*)ubuffer
);
513 __cficu_ucal_setTimeZone(new_cal
, ubuffer
, ucnt
, &status
);
515 if (df
->_property
._GregorianStartDate
!= NULL
) {
516 status
= U_ZERO_ERROR
;
517 CFAbsoluteTime at
= CFDateGetAbsoluteTime((CFDateRef
)df
->_property
._GregorianStartDate
);
518 UDate udate
= (at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000.0;
519 __cficu_ucal_setGregorianChange(new_cal
, udate
, &status
);
520 } else if (calName
&& CFEqual(calName
, kCFCalendarIdentifierGregorian
)) {
521 status
= U_ZERO_ERROR
;
522 UDate udate
= __cficu_ucal_getGregorianChange(cal
, &status
);
523 CFAbsoluteTime at
= U_SUCCESS(status
) ? (udate
/ 1000.0 - kCFAbsoluteTimeIntervalSince1970
) : -13197600000.0; // Oct 15, 1582
524 udate
= (at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000.0;
525 status
= U_ZERO_ERROR
;
526 __cficu_ucal_setGregorianChange(new_cal
, udate
, &status
);
528 if (df
->_property
._Calendar
!= NULL
) {
529 __cficu_ucal_setAttribute(new_cal
, UCAL_FIRST_DAY_OF_WEEK
, CFCalendarGetFirstWeekday((CFCalendarRef
)df
->_property
._Calendar
));
530 } else if (df
->_property
._CustomFirstWeekday
!= NULL
) {
531 CFNumberRef firstWeekday
= (CFNumberRef
)CFDictionaryGetValue(df
->_property
._CustomFirstWeekday
, calName
);
532 if (NULL
!= firstWeekday
&& CFGetTypeID(firstWeekday
) == CFNumberGetTypeID()) {
534 if (CFNumberGetValue((CFNumberRef
)firstWeekday
, kCFNumberCFIndexType
, &wkdy
)) {
535 status
= U_ZERO_ERROR
;
536 __cficu_ucal_setAttribute(new_cal
, UCAL_FIRST_DAY_OF_WEEK
, wkdy
);
541 if (df
->_property
._Calendar
!= NULL
) {
542 __cficu_ucal_setAttribute(new_cal
, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
, CFCalendarGetMinimumDaysInFirstWeek((CFCalendarRef
)df
->_property
._Calendar
));
543 } else if (df
->_property
._CustomMinDaysInFirstWeek
!= NULL
) {
544 CFNumberRef minDays
= (CFNumberRef
)CFDictionaryGetValue(df
->_property
._CustomMinDaysInFirstWeek
, calName
);
545 if (NULL
!= minDays
&& CFGetTypeID(minDays
) == CFNumberGetTypeID()) {
547 if (CFNumberGetValue((CFNumberRef
)minDays
, kCFNumberCFIndexType
, &mwd
)) {
548 status
= U_ZERO_ERROR
;
549 __cficu_ucal_setAttribute(new_cal
, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
, mwd
);
553 __cficu_udat_setCalendar(df
->_df
, new_cal
);
554 __cficu_ucal_close(new_cal
);
557 #define RESET_PROPERTY(C, K) \
558 if (df->_property. C) __CFDateFormatterSetProperty(df, K, df->_property. C, true);
560 static void __ResetUDateFormat(CFDateFormatterRef df
, Boolean goingToHaveCustomFormat
) {
561 if (df
->_df
) __cficu_udat_close(df
->_df
);
564 // uses _timeStyle, _dateStyle, _locale, _property._TimeZone; sets _df, _format, _defformat
565 char loc_buffer
[BUFFER_SIZE
];
567 CFStringRef tmpLocName
= df
->_locale
? CFLocaleGetIdentifier(df
->_locale
) : CFSTR("");
568 CFStringGetCString(tmpLocName
, loc_buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
);
570 UChar tz_buffer
[BUFFER_SIZE
];
572 CFStringRef tmpTZName
= df
->_property
._TimeZone
? CFTimeZoneGetName(df
->_property
._TimeZone
) : CFSTR("GMT");
573 CFStringGetCharacters(tmpTZName
, CFRangeMake(0, CFStringGetLength(tmpTZName
)), (UniChar
*)tz_buffer
);
575 int32_t udstyle
= 0, utstyle
= 0; // effectively this makes UDAT_FULL the default for unknown dateStyle/timeStyle values
576 switch (df
->_dateStyle
) {
577 case kCFDateFormatterNoStyle
: udstyle
= UDAT_NONE
; break;
578 case kCFDateFormatterShortStyle
: udstyle
= UDAT_SHORT
; break;
579 case kCFDateFormatterMediumStyle
: udstyle
= UDAT_MEDIUM
; break;
580 case kCFDateFormatterLongStyle
: udstyle
= UDAT_LONG
; break;
581 case kCFDateFormatterFullStyle
: udstyle
= UDAT_FULL
; break;
583 switch (df
->_timeStyle
) {
584 case kCFDateFormatterNoStyle
: utstyle
= UDAT_NONE
; break;
585 case kCFDateFormatterShortStyle
: utstyle
= UDAT_SHORT
; break;
586 case kCFDateFormatterMediumStyle
: utstyle
= UDAT_MEDIUM
; break;
587 case kCFDateFormatterLongStyle
: utstyle
= UDAT_LONG
; break;
588 case kCFDateFormatterFullStyle
: utstyle
= UDAT_FULL
; break;
590 Boolean wantRelative
= (NULL
!= df
->_property
._DoesRelativeDateFormatting
&& df
->_property
._DoesRelativeDateFormatting
== kCFBooleanTrue
);
591 Boolean hasFormat
= (NULL
!= df
->_property
._HasCustomFormat
&& df
->_property
._HasCustomFormat
== kCFBooleanTrue
) || goingToHaveCustomFormat
;
592 if (wantRelative
&& !hasFormat
&& kCFDateFormatterNoStyle
!= df
->_dateStyle
) {
593 udstyle
|= UDAT_RELATIVE
;
596 UErrorCode status
= U_ZERO_ERROR
;
597 UDateFormat
*icudf
= __cficu_udat_open((UDateFormatStyle
)utstyle
, (UDateFormatStyle
)udstyle
, loc_buffer
, tz_buffer
, CFStringGetLength(tmpTZName
), NULL
, 0, &status
);
598 if (NULL
== icudf
|| U_FAILURE(status
)) {
601 if (df
->_property
._IsLenient
!= NULL
) {
602 __cficu_udat_setLenient(icudf
, (kCFBooleanTrue
== df
->_property
._IsLenient
));
604 __cficu_udat_setLenient(icudf
, 0);
606 if (kCFDateFormatterNoStyle
== df
->_dateStyle
&& kCFDateFormatterNoStyle
== df
->_timeStyle
) {
607 if (wantRelative
&& !hasFormat
&& kCFDateFormatterNoStyle
!= df
->_dateStyle
) {
608 UErrorCode s
= U_ZERO_ERROR
;
609 __cficu_udat_applyPatternRelative(icudf
, NULL
, 0, NULL
, 0, &s
);
611 __cficu_udat_applyPattern(icudf
, false, NULL
, 0);
614 if (!wantRelative
&& df
->_property
._HasCustomFormat
== kCFBooleanTrue
) {
615 CFIndex cnt
= CFStringGetLength(df
->_format
);
616 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
617 const UChar
*ustr
= (UChar
*)CFStringGetCharactersPtr((CFStringRef
)df
->_format
);
619 CFStringGetCharacters(df
->_format
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
622 __cficu_udat_applyPattern(icudf
, false, ustr
, cnt
);
625 CFStringRef calident
= (CFStringRef
)CFLocaleGetValue(df
->_locale
, kCFLocaleCalendarIdentifierKey
);
626 if (calident
&& CFEqual(calident
, kCFCalendarIdentifierGregorian
)) {
627 status
= U_ZERO_ERROR
;
628 __cficu_udat_set2DigitYearStart(icudf
, -631152000000.0, &status
); // 1950-01-01 00:00:00 GMT
632 __ReadCustomUDateFormatProperty(df
);
634 __SetCalendarProperties(df
);
636 if (wantRelative
&& !hasFormat
&& kCFDateFormatterNoStyle
!= df
->_dateStyle
) {
637 __substituteFormatStringFromPrefsDFRelative(df
);
639 __substituteFormatStringFromPrefsDF(df
, false);
640 __substituteFormatStringFromPrefsDF(df
, true);
643 __ApplyUDateFormatSymbol(df
);
646 if (wantRelative
&& !hasFormat
&& kCFDateFormatterNoStyle
!= df
->_dateStyle
) {
647 UChar dateBuffer
[BUFFER_SIZE
];
648 UChar timeBuffer
[BUFFER_SIZE
];
649 status
= U_ZERO_ERROR
;
650 CFIndex dateLen
= __cficu_udat_toPatternRelativeDate(icudf
, dateBuffer
, BUFFER_SIZE
, &status
);
651 CFIndex timeLen
= (utstyle
!= UDAT_NONE
) ? __cficu_udat_toPatternRelativeTime(icudf
, timeBuffer
, BUFFER_SIZE
, &status
) : 0;
652 if (U_SUCCESS(status
) && dateLen
<= BUFFER_SIZE
&& timeLen
<= BUFFER_SIZE
) {
653 // We assume that the 12/24-hour forcing preferences only affect the Time component
654 CFStringRef newFormat
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)timeBuffer
, timeLen
);
655 CFStringRef formatString
= __CFDateFormatterCreateForcedString(df
, newFormat
);
656 CFIndex cnt
= CFStringGetLength(formatString
);
657 CFAssert1(cnt
<= BUFFER_SIZE
, __kCFLogAssertion
, "%s(): time format string too long", __PRETTY_FUNCTION__
);
658 if (cnt
<= BUFFER_SIZE
) {
659 CFStringGetCharacters(formatString
, CFRangeMake(0, cnt
), (UniChar
*)timeBuffer
);
661 status
= U_ZERO_ERROR
;
662 __cficu_udat_applyPatternRelative(icudf
, dateBuffer
, dateLen
, timeBuffer
, timeLen
, &status
);
663 // ignore error and proceed anyway, what else can be done?
665 UChar ubuffer
[BUFFER_SIZE
];
666 status
= U_ZERO_ERROR
;
667 int32_t ret
= __cficu_udat_toPattern(icudf
, false, ubuffer
, BUFFER_SIZE
, &status
); // read out current pattern
668 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
669 if (df
->_format
) CFRelease(df
->_format
);
670 df
->_format
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, ret
);
673 CFRelease(formatString
);
674 CFRelease(newFormat
);
677 UChar ubuffer
[BUFFER_SIZE
];
678 status
= U_ZERO_ERROR
;
679 int32_t ret
= __cficu_udat_toPattern(icudf
, false, ubuffer
, BUFFER_SIZE
, &status
);
680 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
681 CFStringRef newFormat
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, ret
);
682 CFStringRef formatString
= __CFDateFormatterCreateForcedString(df
, newFormat
);
683 CFIndex cnt
= CFStringGetLength(formatString
);
684 CFAssert1(cnt
<= 1024, __kCFLogAssertion
, "%s(): format string too long", __PRETTY_FUNCTION__
);
685 if (df
->_format
!= formatString
&& cnt
<= 1024) {
686 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
687 const UChar
*ustr
= (UChar
*)CFStringGetCharactersPtr((CFStringRef
)formatString
);
689 CFStringGetCharacters(formatString
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
692 UErrorCode status
= U_ZERO_ERROR
;
693 // __cficu_udat_applyPattern(df->_df, false, ustr, cnt, &status);
694 __cficu_udat_applyPattern(df
->_df
, false, ustr
, cnt
);
695 if (U_SUCCESS(status
)) {
696 if (df
->_format
) CFRelease(df
->_format
);
697 df
->_format
= (CFStringRef
)CFStringCreateCopy(CFGetAllocator(df
), formatString
);
700 CFRelease(formatString
);
701 CFRelease(newFormat
);
704 if (df
->_defformat
) CFRelease(df
->_defformat
);
705 df
->_defformat
= df
->_format
? (CFStringRef
)CFRetain(df
->_format
) : NULL
;
707 RESET_PROPERTY(_IsLenient
, kCFDateFormatterIsLenientKey
);
708 RESET_PROPERTY(_DoesRelativeDateFormatting
, kCFDateFormatterDoesRelativeDateFormattingKey
);
709 RESET_PROPERTY(_Calendar
, kCFDateFormatterCalendarKey
);
710 RESET_PROPERTY(_CalendarName
, kCFDateFormatterCalendarIdentifierKey
);
711 RESET_PROPERTY(_TimeZone
, kCFDateFormatterTimeZoneKey
);
712 RESET_PROPERTY(_TwoDigitStartDate
, kCFDateFormatterTwoDigitStartDateKey
);
713 RESET_PROPERTY(_DefaultDate
, kCFDateFormatterDefaultDateKey
);
714 RESET_PROPERTY(_GregorianStartDate
, kCFDateFormatterGregorianStartDateKey
);
715 RESET_PROPERTY(_AmbiguousYearStrategy
, kCFDateFormatterAmbiguousYearStrategyKey
);
716 RESET_PROPERTY(_UsesCharacterDirection
, kCFDateFormatterUsesCharacterDirectionKey
);
719 static CFTypeID __kCFDateFormatterTypeID
= _kCFRuntimeNotATypeID
;
721 static const CFRuntimeClass __CFDateFormatterClass
= {
726 __CFDateFormatterDeallocate
,
730 __CFDateFormatterCopyDescription
733 static void __CFDateFormatterInitialize(void) {
734 __kCFDateFormatterTypeID
= _CFRuntimeRegisterClass(&__CFDateFormatterClass
);
737 CFTypeID
CFDateFormatterGetTypeID(void) {
738 if (_kCFRuntimeNotATypeID
== __kCFDateFormatterTypeID
) __CFDateFormatterInitialize();
739 return __kCFDateFormatterTypeID
;
742 CFDateFormatterRef
CFDateFormatterCreate(CFAllocatorRef allocator
, CFLocaleRef locale
, CFDateFormatterStyle dateStyle
, CFDateFormatterStyle timeStyle
) {
743 struct __CFDateFormatter
*memory
;
744 uint32_t size
= sizeof(struct __CFDateFormatter
) - sizeof(CFRuntimeBase
);
745 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
746 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
747 if (locale
) __CFGenericValidateType(locale
, CFLocaleGetTypeID());
748 memory
= (struct __CFDateFormatter
*)_CFRuntimeCreateInstance(allocator
, CFDateFormatterGetTypeID(), size
, NULL
);
749 if (NULL
== memory
) {
753 memory
->_locale
= NULL
;
754 memory
->_format
= NULL
;
755 memory
->_defformat
= NULL
;
756 memory
->_dateStyle
= dateStyle
;
757 memory
->_timeStyle
= timeStyle
;
758 memory
->_property
._IsLenient
= NULL
;
759 memory
->_property
._DoesRelativeDateFormatting
= NULL
;
760 memory
->_property
._HasCustomFormat
= NULL
;
761 memory
->_property
._TimeZone
= NULL
;
762 memory
->_property
._Calendar
= NULL
;
763 memory
->_property
._CalendarName
= NULL
;
764 memory
->_property
._TwoDigitStartDate
= NULL
;
765 memory
->_property
._DefaultDate
= NULL
;
766 memory
->_property
._GregorianStartDate
= NULL
;
767 memory
->_property
._EraSymbols
= NULL
;
768 memory
->_property
._LongEraSymbols
= NULL
;
769 memory
->_property
._MonthSymbols
= NULL
;
770 memory
->_property
._ShortMonthSymbols
= NULL
;
771 memory
->_property
._VeryShortMonthSymbols
= NULL
;
772 memory
->_property
._StandaloneMonthSymbols
= NULL
;
773 memory
->_property
._ShortStandaloneMonthSymbols
= NULL
;
774 memory
->_property
._VeryShortStandaloneMonthSymbols
= NULL
;
775 memory
->_property
._WeekdaySymbols
= NULL
;
776 memory
->_property
._ShortWeekdaySymbols
= NULL
;
777 memory
->_property
._VeryShortWeekdaySymbols
= NULL
;
778 memory
->_property
._StandaloneWeekdaySymbols
= NULL
;
779 memory
->_property
._ShortStandaloneWeekdaySymbols
= NULL
;
780 memory
->_property
._VeryShortStandaloneWeekdaySymbols
= NULL
;
781 memory
->_property
._QuarterSymbols
= NULL
;
782 memory
->_property
._ShortQuarterSymbols
= NULL
;
783 memory
->_property
._StandaloneQuarterSymbols
= NULL
;
784 memory
->_property
._ShortStandaloneQuarterSymbols
= NULL
;
785 memory
->_property
._AMSymbol
= NULL
;
786 memory
->_property
._PMSymbol
= NULL
;
787 memory
->_property
._AmbiguousYearStrategy
= NULL
;
788 memory
->_property
._UsesCharacterDirection
= NULL
;
789 memory
->_property
._CustomEraSymbols
= NULL
;
790 memory
->_property
._CustomMonthSymbols
= NULL
;
791 memory
->_property
._CustomShortMonthSymbols
= NULL
;
792 memory
->_property
._CustomWeekdaySymbols
= NULL
;
793 memory
->_property
._CustomShortWeekdaySymbols
= NULL
;
794 memory
->_property
._CustomLongEraSymbols
= NULL
;
795 memory
->_property
._CustomVeryShortMonthSymbols
= NULL
;
796 memory
->_property
._CustomVeryShortWeekdaySymbols
= NULL
;
797 memory
->_property
._CustomStandaloneMonthSymbols
= NULL
;
798 memory
->_property
._CustomShortStandaloneMonthSymbols
= NULL
;
799 memory
->_property
._CustomVeryShortStandaloneMonthSymbols
= NULL
;
800 memory
->_property
._CustomStandaloneWeekdaySymbols
= NULL
;
801 memory
->_property
._CustomShortStandaloneWeekdaySymbols
= NULL
;
802 memory
->_property
._CustomVeryShortStandaloneWeekdaySymbols
= NULL
;
803 memory
->_property
._CustomQuarterSymbols
= NULL
;
804 memory
->_property
._CustomShortQuarterSymbols
= NULL
;
805 memory
->_property
._CustomStandaloneQuarterSymbols
= NULL
;
806 memory
->_property
._CustomShortStandaloneQuarterSymbols
= NULL
;
807 memory
->_property
._CustomDateFormat
= NULL
;
808 memory
->_property
._CustomTimeFormat
= NULL
;
809 memory
->_property
._Custom24Hour
= NULL
;
810 memory
->_property
._Custom12Hour
= NULL
;
811 memory
->_property
._CustomAMSymbol
= NULL
;
812 memory
->_property
._CustomPMSymbol
= NULL
;
813 memory
->_property
._CustomFirstWeekday
= NULL
;
814 memory
->_property
._CustomMinDaysInFirstWeek
= NULL
;
817 case kCFDateFormatterNoStyle
:
818 case kCFDateFormatterShortStyle
:
819 case kCFDateFormatterMediumStyle
:
820 case kCFDateFormatterLongStyle
:
821 case kCFDateFormatterFullStyle
: break;
823 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown date style %d", __PRETTY_FUNCTION__
, dateStyle
);
824 memory
->_dateStyle
= kCFDateFormatterMediumStyle
;
828 case kCFDateFormatterNoStyle
:
829 case kCFDateFormatterShortStyle
:
830 case kCFDateFormatterMediumStyle
:
831 case kCFDateFormatterLongStyle
:
832 case kCFDateFormatterFullStyle
: break;
834 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown time style %d", __PRETTY_FUNCTION__
, timeStyle
);
835 memory
->_timeStyle
= kCFDateFormatterMediumStyle
;
839 memory
->_locale
= locale
? CFLocaleCreateCopy(allocator
, locale
) : (CFLocaleRef
)CFRetain(CFLocaleGetSystem());
840 memory
->_property
._TimeZone
= CFTimeZoneCopyDefault();
842 CFStringRef calident
= (CFStringRef
)CFLocaleGetValue(memory
->_locale
, kCFLocaleCalendarIdentifierKey
);
843 if (calident
&& CFEqual(calident
, kCFCalendarIdentifierGregorian
)) {
844 memory
->_property
._TwoDigitStartDate
= CFDateCreate(kCFAllocatorSystemDefault
, -1609459200.0); // 1950-01-01 00:00:00 +0000
847 __ResetUDateFormat(memory
, false);
852 return (CFDateFormatterRef
)memory
;
855 static void __substituteFormatStringFromPrefsDFRelative(CFDateFormatterRef formatter
) {
857 CFIndex dateLen
= -1;
858 UChar dateBuffer
[BUFFER_SIZE
];
859 if (kCFDateFormatterNoStyle
!= formatter
->_dateStyle
) {
860 if (formatter
->_property
._CustomDateFormat
!= NULL
) {
861 dateLen
= __CFMin(CFStringGetLength(formatter
->_property
._CustomDateFormat
), BUFFER_SIZE
);
862 CFStringGetCharacters(formatter
->_property
._CustomDateFormat
, CFRangeMake(0, dateLen
), (UniChar
*)dateBuffer
);
866 UErrorCode status
= U_ZERO_ERROR
;
867 int32_t ret
= __cficu_udat_toPatternRelativeDate(formatter
->_df
, dateBuffer
, BUFFER_SIZE
, &status
);
868 if (!U_FAILURE(status
)) {
873 CFIndex timeLen
= -1;
874 UChar timeBuffer
[BUFFER_SIZE
];
875 if (kCFDateFormatterNoStyle
!= formatter
->_timeStyle
) {
876 if (formatter
->_property
._CustomTimeFormat
!= NULL
) {
877 timeLen
= __CFMin(CFStringGetLength(formatter
->_property
._CustomTimeFormat
), BUFFER_SIZE
);
878 CFStringGetCharacters(formatter
->_property
._CustomTimeFormat
, CFRangeMake(0, timeLen
), (UniChar
*)timeBuffer
);
882 UErrorCode status
= U_ZERO_ERROR
;
883 int32_t ret
= __cficu_udat_toPatternRelativeTime(formatter
->_df
, timeBuffer
, BUFFER_SIZE
, &status
);
884 if (!U_FAILURE(status
)) {
889 UErrorCode status
= U_ZERO_ERROR
;
890 __cficu_udat_applyPatternRelative(formatter
->_df
, (0 <= dateLen
) ? dateBuffer
: NULL
, (0 <= dateLen
) ? dateLen
: 0, (0 <= timeLen
) ? timeBuffer
: NULL
, (0 <= timeLen
) ? timeLen
: 0, &status
);
893 static void __substituteFormatStringFromPrefsDF(CFDateFormatterRef formatter
, bool doTime
) {
894 CFIndex formatStyle
= doTime
? formatter
->_timeStyle
: formatter
->_dateStyle
;
895 CFStringRef pref
= doTime
? formatter
->_property
._CustomTimeFormat
: formatter
->_property
._CustomDateFormat
;
896 if (kCFDateFormatterNoStyle
!= formatStyle
) {
898 int32_t icustyle
= UDAT_NONE
;
899 switch (formatStyle
) {
900 case kCFDateFormatterShortStyle
: icustyle
= UDAT_SHORT
; break;
901 case kCFDateFormatterMediumStyle
: icustyle
= UDAT_MEDIUM
; break;
902 case kCFDateFormatterLongStyle
: icustyle
= UDAT_LONG
; break;
903 case kCFDateFormatterFullStyle
: icustyle
= UDAT_FULL
; break;
905 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
906 char buffer
[BUFFER_SIZE
];
907 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
909 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
911 UErrorCode status
= U_ZERO_ERROR
;
912 UDateFormat
*df
= __cficu_udat_open((UDateFormatStyle
)(doTime
? icustyle
: UDAT_NONE
), (UDateFormatStyle
)(doTime
? UDAT_NONE
: icustyle
), cstr
, NULL
, 0, NULL
, 0, &status
);
914 UChar ubuffer
[BUFFER_SIZE
];
915 status
= U_ZERO_ERROR
;
916 int32_t date_len
= __cficu_udat_toPattern(df
, false, ubuffer
, BUFFER_SIZE
, &status
);
917 if (U_SUCCESS(status
) && date_len
<= BUFFER_SIZE
) {
918 CFStringRef dateString
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)ubuffer
, date_len
);
919 status
= U_ZERO_ERROR
;
920 int32_t formatter_len
= __cficu_udat_toPattern(formatter
->_df
, false, ubuffer
, BUFFER_SIZE
, &status
);
921 if (U_SUCCESS(status
) && formatter_len
<= BUFFER_SIZE
) {
922 CFMutableStringRef formatString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
923 CFStringAppendCharacters(formatString
, (UniChar
*)ubuffer
, formatter_len
);
924 // find dateString inside formatString, substitute the pref in that range
926 if (CFStringFindWithOptions(formatString
, dateString
, CFRangeMake(0, formatter_len
), 0, &result
)) {
927 CFStringReplace(formatString
, result
, pref
);
928 int32_t new_len
= CFStringGetLength(formatString
);
929 STACK_BUFFER_DECL(UChar
, new_buffer
, new_len
);
930 const UChar
*new_ustr
= (UChar
*)CFStringGetCharactersPtr(formatString
);
931 if (NULL
== new_ustr
) {
932 CFStringGetCharacters(formatString
, CFRangeMake(0, new_len
), (UniChar
*)new_buffer
);
933 new_ustr
= new_buffer
;
935 status
= U_ZERO_ERROR
;
936 // __cficu_udat_applyPattern(formatter->_df, false, new_ustr, new_len, &status);
937 __cficu_udat_applyPattern(formatter
->_df
, false, new_ustr
, new_len
);
939 CFRelease(formatString
);
941 CFRelease(dateString
);
943 __cficu_udat_close(df
);
949 static void __CFDateFormatterStoreSymbolPrefs(const void *key
, const void *value
, void *context
) {
950 if (CFGetTypeID(key
) == CFStringGetTypeID() && CFGetTypeID(value
) == CFArrayGetTypeID()) {
951 CFDateFormatterRef formatter
= (CFDateFormatterRef
)context
;
952 UDateFormatSymbolType sym
= (UDateFormatSymbolType
)CFStringGetIntValue((CFStringRef
)key
);
953 CFArrayRef array
= (CFArrayRef
)value
;
954 CFIndex idx
, cnt
= CFArrayGetCount(array
);
957 formatter
->_property
._CustomEraSymbols
= (CFArrayRef
)CFRetain(array
);
960 formatter
->_property
._CustomMonthSymbols
= (CFArrayRef
)CFRetain(array
);
962 case UDAT_SHORT_MONTHS
:
963 formatter
->_property
._CustomShortMonthSymbols
= (CFArrayRef
)CFRetain(array
);
966 formatter
->_property
._CustomWeekdaySymbols
= (CFArrayRef
)CFRetain(array
);
968 case UDAT_SHORT_WEEKDAYS
:
969 formatter
->_property
._CustomShortWeekdaySymbols
= (CFArrayRef
)CFRetain(array
);
973 for (idx
= 0; idx
< cnt
; idx
++) {
974 CFStringRef item
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
975 if (CFGetTypeID(item
) != CFStringGetTypeID()) continue;
977 formatter
->_property
._CustomAMSymbol
= (CFStringRef
)CFRetain(item
);
978 } else if (idx
== 1) {
979 formatter
->_property
._CustomPMSymbol
= (CFStringRef
)CFRetain(item
);
985 formatter
->_property
._CustomLongEraSymbols
= (CFArrayRef
)CFRetain(array
);
987 case UDAT_NARROW_MONTHS
:
988 formatter
->_property
._CustomVeryShortMonthSymbols
= (CFArrayRef
)CFRetain(array
);
990 case UDAT_NARROW_WEEKDAYS
:
991 formatter
->_property
._CustomVeryShortWeekdaySymbols
= (CFArrayRef
)CFRetain(array
);
993 case UDAT_STANDALONE_MONTHS
:
994 formatter
->_property
._CustomStandaloneMonthSymbols
= (CFArrayRef
)CFRetain(array
);
996 case UDAT_STANDALONE_SHORT_MONTHS
:
997 formatter
->_property
._CustomShortStandaloneMonthSymbols
= (CFArrayRef
)CFRetain(array
);
999 case UDAT_STANDALONE_NARROW_MONTHS
:
1000 formatter
->_property
._CustomVeryShortStandaloneMonthSymbols
= (CFArrayRef
)CFRetain(array
);
1002 case UDAT_STANDALONE_WEEKDAYS
:
1003 formatter
->_property
._CustomStandaloneWeekdaySymbols
= (CFArrayRef
)CFRetain(array
);
1005 case UDAT_STANDALONE_SHORT_WEEKDAYS
:
1006 formatter
->_property
._CustomShortStandaloneWeekdaySymbols
= (CFArrayRef
)CFRetain(array
);
1008 case UDAT_STANDALONE_NARROW_WEEKDAYS
:
1009 formatter
->_property
._CustomVeryShortStandaloneWeekdaySymbols
= (CFArrayRef
)CFRetain(array
);
1012 formatter
->_property
._CustomQuarterSymbols
= (CFArrayRef
)CFRetain(array
);
1014 case UDAT_SHORT_QUARTERS
:
1015 formatter
->_property
._CustomShortQuarterSymbols
= (CFArrayRef
)CFRetain(array
);
1017 case UDAT_STANDALONE_QUARTERS
:
1018 formatter
->_property
._CustomStandaloneQuarterSymbols
= (CFArrayRef
)CFRetain(array
);
1020 case UDAT_STANDALONE_SHORT_QUARTERS
:
1021 formatter
->_property
._CustomShortStandaloneQuarterSymbols
= (CFArrayRef
)CFRetain(array
);
1029 static CFStringRef
__CFDateFormatterCreateForcedTemplate(CFLocaleRef locale
, CFStringRef inString
) {
1030 if (!inString
) return NULL
;
1032 Boolean doForce24
= false, doForce12
= false;
1033 CFDictionaryRef prefs
= __CFLocaleGetPrefs(locale
);
1034 CFPropertyListRef pref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUForce24HourTime")) : NULL
;
1035 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFBooleanGetTypeID()) {
1036 doForce24
= CFBooleanGetValue((CFBooleanRef
)pref
);
1038 pref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUForce12HourTime")) : NULL
;
1039 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFBooleanGetTypeID()) {
1040 doForce12
= CFBooleanGetValue((CFBooleanRef
)pref
);
1042 if (doForce24
) doForce12
= false; // if both are set, Force24 wins, period
1043 if (!doForce24
&& !doForce12
) return (CFStringRef
)CFRetain(inString
);
1045 CFMutableStringRef outString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
1046 CFIndex cnt
= CFStringGetLength(inString
);
1047 CFIndex lastSecond
= -1, lastMinute
= -1, firstHour
= -1;
1048 Boolean isInQuote
= false, hasA
= false, had12Hour
= false, had24Hour
= false;
1049 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1050 Boolean emit
= true;
1051 UniChar ch
= CFStringGetCharacterAtIndex(inString
, idx
);
1053 case '\'': isInQuote
= !isInQuote
; break;
1054 case 'j': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); if (doForce24
) ch
= 'H'; else ch
= 'h';} break;
1055 case 'h': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had12Hour
= true; if (doForce24
) ch
= 'H';} break; // switch 12-hour to 24-hour
1056 case 'K': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had12Hour
= true; if (doForce24
) ch
= 'k';} break; // switch 12-hour to 24-hour
1057 case 'H': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had24Hour
= true; if (doForce12
) ch
= 'h';} break; // switch 24-hour to 12-hour
1058 case 'k': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had24Hour
= true; if (doForce12
) ch
= 'K';} break; // switch 24-hour to 12-hour
1059 case 'm': if (!isInQuote
) lastMinute
= CFStringGetLength(outString
); break;
1060 case 's': if (!isInQuote
) lastSecond
= CFStringGetLength(outString
); break;
1061 case 'a': if (!isInQuote
) {hasA
= true; if (doForce24
) emit
= false;} break;
1064 if (emit
) CFStringAppendCharacters(outString
, &ch
, 1);
1071 Mapping H<->h and K<->k is not correct in all locales; Japanese 12 hour, for example, uses H<->k
1072 This gets an approximately correct replacement character for the locale and forcing direction in question
1073 <rdar://problem/14062096> [iCal] Incorrect time format is used for current time indicator line
1075 static UChar
__CFDateFormatterForcedHourCharacterForLocale(CFLocaleRef locale
, Boolean doForce24
, Boolean doForce12
, Boolean
*succeeded
) {
1076 if (doForce24
) doForce12
= false; // if both are set, Force24 wins, period
1077 if (!locale
|| (!doForce24
&& !doForce12
)) {
1081 CFStringRef localeName
= locale
? CFLocaleGetIdentifier(locale
) : CFSTR("");
1082 char buffer
[BUFFER_SIZE
] = {0};
1083 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
1085 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
1088 __block UChar hourPatternChar
= '\0';
1090 useTemplatePatternGenerator(cstr
, ^(UDateTimePatternGenerator
*ptg
) {
1091 UChar hourPattern
[256] = {0};
1092 int32_t patternLen
= -1;
1094 UErrorCode errorCode
= U_ZERO_ERROR
;
1095 patternLen
= __cficu_udatpg_getBestPattern(ptg
, (const UChar
*)(doForce12
? "h" : "H"), 1, hourPattern
, sizeof(hourPattern
) / sizeof(UChar
), &errorCode
);
1096 if (errorCode
!= U_ZERO_ERROR
) {
1097 memset(hourPattern
, 0, sizeof(hourPattern
)); //make sure there's nothing there if we failed
1103 Blindly replacing HHHH with four copies of the entire udatpg_getBestPattern result is not going to work. Search for the first [hHkK] in the result and use just that
1105 if (patternLen
> 0) {
1106 for (CFIndex idx
= 0; hourPattern
[idx
] != '\0' && idx
< patternLen
&& idx
< sizeof(hourPattern
) / sizeof(UChar
); idx
++) {
1107 if (hourPattern
[idx
] == 'k' || hourPattern
[idx
] == 'K' || hourPattern
[idx
] == 'h' || hourPattern
[idx
] == 'H') {
1108 hourPatternChar
= hourPattern
[idx
];
1115 *succeeded
= hourPatternChar
!= '\0';
1116 return hourPatternChar
;
1119 #define FORCE_CHAR(replacement, oldType, newType) do { \
1121 if (-1 == firstHour) {\
1122 firstHour = CFStringGetLength(outString);\
1124 had##oldType##Hour = true;\
1125 if (doForce##newType) {\
1126 ch = useSpecialHourChar ? hourPatternChar : replacement;\
1130 #define FORCE_CHAR_12(replacement) FORCE_CHAR(replacement, 12, 24)
1131 #define FORCE_CHAR_24(replacement) FORCE_CHAR(replacement, 24, 12)
1133 static CFStringRef
__CFDateFormatterCreateForcedString(CFDateFormatterRef formatter
, CFStringRef inString
) {
1134 if (!inString
) return NULL
;
1136 Boolean doForce24
= false, doForce12
= false;
1137 if (formatter
->_property
._Custom24Hour
!= NULL
) {
1138 doForce24
= CFBooleanGetValue((CFBooleanRef
)formatter
->_property
._Custom24Hour
);
1140 if (formatter
->_property
._Custom12Hour
!= NULL
) {
1141 doForce12
= CFBooleanGetValue((CFBooleanRef
)formatter
->_property
._Custom12Hour
);
1143 if (doForce24
) doForce12
= false; // if both are set, Force24 wins, period
1145 static CFCharacterSetRef hourCharacters
;
1146 static dispatch_once_t onceToken
;
1147 dispatch_once(&onceToken
, ^{
1148 hourCharacters
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorSystemDefault
, CFSTR("hHkK"));
1151 CFRange hourRange
= CFRangeMake(kCFNotFound
, 0);
1152 if (!CFStringFindCharacterFromSet(inString
, hourCharacters
, CFRangeMake(0, CFStringGetLength(inString
)), 0, &hourRange
) || hourRange
.location
== kCFNotFound
) {
1157 if (!doForce24
&& !doForce12
) return (CFStringRef
)CFRetain(inString
);
1159 Boolean useSpecialHourChar
= false;
1160 UChar hourPatternChar
= __CFDateFormatterForcedHourCharacterForLocale(formatter
->_locale
, doForce24
, doForce12
, &useSpecialHourChar
);
1162 CFMutableStringRef outString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
1163 CFIndex cnt
= CFStringGetLength(inString
);
1164 CFIndex lastSecond
= -1, lastMinute
= -1, firstHour
= -1;
1165 Boolean isInQuote
= false, hasA
= false, had12Hour
= false, had24Hour
= false;
1166 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1167 Boolean emit
= true;
1168 UniChar ch
= CFStringGetCharacterAtIndex(inString
, idx
);
1170 case '\'': isInQuote
= !isInQuote
; break;
1171 case 'h': FORCE_CHAR_12('H'); break; // switch 12-hour to 24-hour
1172 case 'k': FORCE_CHAR_24('K'); break; // switch 24-hour to 12-hour
1173 case 'H': FORCE_CHAR_24('h'); break; // switch 24-hour to 12-hour
1174 case 'K': FORCE_CHAR_12('k'); break; // switch 12-hour to 24-hour
1175 case 'm': if (!isInQuote
) lastMinute
= CFStringGetLength(outString
); break;
1176 case 's': if (!isInQuote
) lastSecond
= CFStringGetLength(outString
); break;
1177 case 'a': if (!isInQuote
) hasA
= true;
1178 if (!isInQuote
&& doForce24
) {
1179 // skip 'a' and one optional trailing space
1181 if (idx
+ 1 < cnt
&& ' ' == CFStringGetCharacterAtIndex(inString
, idx
+ 1)) idx
++;
1185 if (!isInQuote
&& doForce24
) {
1186 // if next character is 'a' AND we have seen the hour designator, skip space and 'a'
1187 if (idx
+ 1 < cnt
&& 'a' == CFStringGetCharacterAtIndex(inString
, idx
+ 1) && -1 != firstHour
) {
1194 if (emit
) CFStringAppendCharacters(outString
, &ch
, 1);
1196 if (doForce12
&& !hasA
&& had24Hour
) {
1197 CFStringRef locName
= CFLocaleGetIdentifier(formatter
->_locale
);
1198 if (-1 != firstHour
&& (CFStringHasPrefix(locName
, CFSTR("ko")) || CFEqual(locName
, CFSTR("zh_SG")))) {
1199 CFStringInsert(outString
, firstHour
, CFSTR("a "));
1200 } else if (-1 != firstHour
&& (CFStringHasPrefix(locName
, CFSTR("zh")) || CFStringHasPrefix(locName
, CFSTR("ja")))) {
1201 CFStringInsert(outString
, firstHour
, CFSTR("a"));
1203 CFIndex lastPos
= (-1 != lastSecond
) ? lastSecond
: ((-1 != lastMinute
) ? lastMinute
: -1);
1204 if (-1 != lastPos
) {
1205 cnt
= CFStringGetLength(outString
);
1207 UniChar ch
= (lastPos
< cnt
) ? CFStringGetCharacterAtIndex(outString
, lastPos
) : 0;
1209 case '\"': lastPos
++; break;
1214 ch
= (lastPos
< cnt
) ? CFStringGetCharacterAtIndex(outString
, lastPos
) : 0;
1215 } while ('\'' != ch
&& '\0' != ch
);
1216 if ('\'' == ch
) lastPos
++;
1217 ch
= (lastPos
< cnt
) ? CFStringGetCharacterAtIndex(outString
, lastPos
) : 0;
1218 if ('\'' == ch
) goto again
;
1221 CFStringInsert(outString
, lastPos
, CFSTR(" a"));
1228 CFLocaleRef
CFDateFormatterGetLocale(CFDateFormatterRef formatter
) {
1229 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1230 return formatter
->_locale
;
1233 CFDateFormatterStyle
CFDateFormatterGetDateStyle(CFDateFormatterRef formatter
) {
1234 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1235 return formatter
->_dateStyle
;
1238 CFDateFormatterStyle
CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter
) {
1239 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1240 return formatter
->_timeStyle
;
1243 CFStringRef
CFDateFormatterGetFormat(CFDateFormatterRef formatter
) {
1244 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1245 return formatter
->_format
;
1248 void CFDateFormatterSetFormat(CFDateFormatterRef formatter
, CFStringRef formatString
) {
1249 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1250 __CFGenericValidateType(formatString
, CFStringGetTypeID());
1251 formatString
= __CFDateFormatterCreateForcedString(formatter
, formatString
);
1252 CFIndex cnt
= CFStringGetLength(formatString
);
1253 CFAssert1(cnt
<= 1024, __kCFLogAssertion
, "%s(): format string too long", __PRETTY_FUNCTION__
);
1254 if (formatter
->_format
!= formatString
&& cnt
<= 1024) {
1255 // When going from a situation where there is no custom format already,
1256 // and the "relative date formatting" property is set, we need to reset
1257 // the whole UDateFormat.
1258 if (formatter
->_property
._HasCustomFormat
!= kCFBooleanTrue
&& formatter
->_property
._DoesRelativeDateFormatting
== kCFBooleanTrue
) {
1259 __ResetUDateFormat(formatter
, true);
1260 // the "true" results in: if you set a custom format string, you don't get relative date formatting
1262 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
1263 const UChar
*ustr
= (UChar
*)CFStringGetCharactersPtr((CFStringRef
)formatString
);
1265 CFStringGetCharacters(formatString
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
1268 UErrorCode status
= U_ZERO_ERROR
;
1269 // __cficu_udat_applyPattern(formatter->_df, false, ustr, cnt, &status);
1270 __cficu_udat_applyPattern(formatter
->_df
, false, ustr
, cnt
);
1271 if (U_SUCCESS(status
)) {
1272 if (formatter
->_format
) CFRelease(formatter
->_format
);
1273 formatter
->_format
= (CFStringRef
)CFStringCreateCopy(CFGetAllocator(formatter
), formatString
);
1274 formatter
->_property
._HasCustomFormat
= kCFBooleanTrue
;
1277 if (formatString
) CFRelease(formatString
);
1280 CFStringRef
CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator
, CFDateFormatterRef formatter
, CFDateRef date
) {
1281 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
1282 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
1283 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1284 __CFGenericValidateType(date
, CFDateGetTypeID());
1285 return CFDateFormatterCreateStringWithAbsoluteTime(allocator
, formatter
, CFDateGetAbsoluteTime(date
));
1288 CFStringRef
CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator
, CFDateFormatterRef formatter
, CFAbsoluteTime at
) {
1289 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
1290 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
1291 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1292 UChar
*ustr
= NULL
, ubuffer
[BUFFER_SIZE
+ 1];
1293 UErrorCode status
= U_ZERO_ERROR
;
1294 CFIndex used
, cnt
= BUFFER_SIZE
;
1295 UDate ud
= (at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000.0 + 0.5;
1296 used
= __cficu_udat_format(formatter
->_df
, ud
, ubuffer
+ 1, cnt
, NULL
, &status
);
1297 if (status
== U_BUFFER_OVERFLOW_ERROR
|| cnt
< used
) {
1298 cnt
= used
+ 1 + 1; // leave room for RTL marker if needed
1299 ustr
= (UChar
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(UChar
) * cnt
, 0);
1300 status
= U_ZERO_ERROR
;
1301 used
= __cficu_udat_format(formatter
->_df
, ud
, ustr
+ 1, cnt
, NULL
, &status
);
1303 CFStringRef string
= NULL
;
1304 if (U_SUCCESS(status
)) {
1305 UniChar
*bufferToUse
= ustr
? (UniChar
*)ustr
: (UniChar
*)ubuffer
;
1306 if (formatter
->_property
._UsesCharacterDirection
== kCFBooleanTrue
&& CFLocaleGetLanguageCharacterDirection(CFLocaleGetIdentifier(formatter
->_locale
)) == kCFLocaleLanguageDirectionRightToLeft
) {
1307 // Insert Unicode RTL marker
1308 bufferToUse
[0] = 0x200F;
1311 // Move past direction marker
1314 string
= CFStringCreateWithCharacters(allocator
, bufferToUse
, used
);
1316 if (ustr
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, ustr
);
1320 static UDate
__CFDateFormatterCorrectTimeWithTarget(UCalendar
*calendar
, UDate at
, int32_t target
, Boolean isEra
, UErrorCode
*status
) {
1321 __cficu_ucal_setMillis(calendar
, at
, status
);
1322 UCalendarDateFields field
= isEra
? UCAL_ERA
: UCAL_YEAR
;
1323 __cficu_ucal_set(calendar
, field
, target
);
1324 return __cficu_ucal_getMillis(calendar
, status
);
1327 static UDate
__CFDateFormatterCorrectTimeToARangeAroundCurrentDate(UCalendar
*calendar
, UDate at
, CFIndex period
, CFIndex pastYears
, CFIndex futureYears
, Boolean isEra
, UErrorCode
*status
) {
1328 __cficu_ucal_setMillis(calendar
, __cficu_ucal_getNow(), status
);
1329 int32_t currYear
= __cficu_ucal_get(calendar
, UCAL_YEAR
, status
);
1330 UCalendarDateFields field
= isEra
? UCAL_ERA
: UCAL_YEAR
;
1331 int32_t currEraOrCentury
= __cficu_ucal_get(calendar
, field
, status
);
1334 currEraOrCentury
= currEraOrCentury
/ 100 * 100; // get century
1337 CFIndex futureMax
= currYear
+ futureYears
;
1338 CFIndex pastMin
= currYear
- pastYears
;
1340 CFRange currRange
, futureRange
, pastRange
;
1341 currRange
.location
= futureRange
.location
= pastRange
.location
= kCFNotFound
;
1342 currRange
.length
= futureRange
.length
= pastRange
.length
= 0;
1344 if (period
< INT_MAX
&& futureMax
>= period
) {
1345 futureRange
.location
= 0;
1346 futureRange
.length
= futureMax
- period
+ 1;
1349 pastRange
.location
= period
+ pastMin
;
1350 pastRange
.length
= period
- pastRange
.location
;
1352 if (pastRange
.location
!= kCFNotFound
) {
1353 currRange
.location
= 0;
1355 currRange
.location
= pastMin
;
1358 if (period
< INT_MAX
&& futureMax
> period
) {
1359 futureRange
.location
= 1,
1360 futureRange
.length
= futureMax
- period
;
1363 pastRange
.location
= period
+ pastMin
;
1364 pastRange
.length
= period
- pastRange
.location
+ 1;
1366 if (pastRange
.location
!= kCFNotFound
) {
1367 currRange
.location
= 1;
1369 currRange
.location
= pastMin
;
1373 currRange
.length
= period
- pastRange
.length
- futureRange
.length
;
1375 __cficu_ucal_setMillis(calendar
, at
, status
);
1376 int32_t atYear
= __cficu_ucal_get(calendar
, UCAL_YEAR
, status
);
1379 currEraOrCentury
+= atYear
;
1382 int32_t offset
= 0; // current era or century
1383 if (pastRange
.location
!= kCFNotFound
&& atYear
>= pastRange
.location
&& atYear
- pastRange
.location
+ 1 <= pastRange
.length
) {
1384 offset
= -1; // past era or century
1385 } else if (futureRange
.location
!= kCFNotFound
&& atYear
>= futureRange
.location
&& atYear
- futureRange
.location
+ 1 <= futureRange
.length
) {
1386 offset
= 1; // next era or century
1388 if (!isEra
) offset
*= 100;
1389 return __CFDateFormatterCorrectTimeWithTarget(calendar
, at
, currEraOrCentury
+offset
, isEra
, status
);
1392 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1393 static int32_t __CFDateFormatterGetMaxYearGivenJapaneseEra(UCalendar
*calendar
, int32_t era
, UErrorCode
*status
) {
1395 __cficu_ucal_clear(calendar
);
1396 __cficu_ucal_set(calendar
, UCAL_ERA
, era
+1);
1397 UDate target
= __cficu_ucal_getMillis(calendar
, status
);
1398 __cficu_ucal_set(calendar
, UCAL_ERA
, era
);
1399 years
= __cficu_ucal_getFieldDifference(calendar
, target
, UCAL_YEAR
, status
);
1404 static Boolean
__CFDateFormatterHandleAmbiguousYear(CFDateFormatterRef formatter
, CFStringRef calendar_id
, UDateFormat
*df
, UCalendar
*cal
, UDate
*at
, const UChar
*ustr
, CFIndex length
, UErrorCode
*status
) {
1405 Boolean success
= true;
1406 int64_t ambigStrat
= kCFDateFormatterAmbiguousYearAssumeToNone
;
1407 if (formatter
->_property
._AmbiguousYearStrategy
) {
1408 CFNumberGetValue(formatter
->_property
._AmbiguousYearStrategy
, kCFNumberSInt64Type
, &ambigStrat
);
1410 if (calendar_id
== kCFCalendarIdentifierChinese
) {
1411 // we default to era 1 if era is missing, however, we cannot just test if the era is 1 becuase we may get era 2 or larger if the year in the string is greater than 60
1412 // now I just assume that the year will not be greater than 600 in the string
1413 if (__cficu_ucal_get(cal
, UCAL_ERA
, status
) < 10) {
1414 switch (ambigStrat
) {
1415 case kCFDateFormatterAmbiguousYearFailToParse
:
1418 case kCFDateFormatterAmbiguousYearAssumeToCurrent
: {
1419 __cficu_ucal_setMillis(cal
, __cficu_ucal_getNow(), status
);
1420 int32_t currEra
= __cficu_ucal_get(cal
, UCAL_ERA
, status
);
1421 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, currEra
, true, status
);
1424 case kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate
:
1425 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 60, 29, 30, true, status
);
1427 case kCFDateFormatterAmbiguousYearAssumeToFuture
:
1428 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 60, 0, 59, true, status
);
1430 case kCFDateFormatterAmbiguousYearAssumeToPast
:
1431 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 60, 59, 0, true, status
);
1433 case kCFDateFormatterAmbiguousYearAssumeToLikelyFuture
:
1434 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 60, 10, 49, true, status
);
1436 case kCFDateFormatterAmbiguousYearAssumeToLikelyPast
:
1437 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 60, 49, 10, true, status
);
1439 case kCFDateFormatterAmbiguousYearAssumeToNone
:
1441 break; // do nothing
1444 } else if (calendar_id
== kCFCalendarIdentifierJapanese
) { // ??? need more work
1445 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1446 __cficu_ucal_clear(cal
);
1447 __cficu_ucal_set(cal
, UCAL_ERA
, 1);
1448 __cficu_udat_parseCalendar(df
, cal
, ustr
, length
, NULL
, status
);
1449 UDate test
= __cficu_ucal_getMillis(cal
, status
);
1450 if (test
!= *at
) { // missing era
1451 __cficu_ucal_setMillis(cal
, *at
, status
);
1452 int32_t givenYear
= __cficu_ucal_get(cal
, UCAL_YEAR
, status
);
1453 __cficu_ucal_setMillis(cal
, __cficu_ucal_getNow(), status
);
1454 int32_t currYear
= __cficu_ucal_get(cal
, UCAL_YEAR
, status
);
1455 int32_t currEra
= __cficu_ucal_get(cal
, UCAL_ERA
, status
);
1456 switch (ambigStrat
) {
1457 case kCFDateFormatterAmbiguousYearFailToParse
:
1460 case kCFDateFormatterAmbiguousYearAssumeToCurrent
:
1461 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, currEra
, true, status
);
1463 case kCFDateFormatterAmbiguousYearAssumeToFuture
:
1464 if (givenYear
< currYear
) { // we only consider current or the future
1466 } else { // current era
1467 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, currEra
, true, status
);
1470 case kCFDateFormatterAmbiguousYearAssumeToPast
:
1471 if (givenYear
> currYear
) { // past era
1473 // we find the closest era that has the given year
1474 // if no era has such given year, we fail the parse
1475 for (CFIndex era
= currEra
-1; era
>= 234; era
--) { // Showa era (234) is the longest era
1476 int32_t years
= __CFDateFormatterGetMaxYearGivenJapaneseEra(cal
, era
, status
);
1477 if (givenYear
> years
) {
1481 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, era
, true, status
);
1484 } else { // current era
1485 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, currEra
, true, status
);
1488 case kCFDateFormatterAmbiguousYearAssumeToLikelyFuture
:
1489 if (givenYear
< currYear
- 10) { // we allow 10 years to the past
1492 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, currEra
, true, status
);
1495 case kCFDateFormatterAmbiguousYearAssumeToLikelyPast
:
1496 if (givenYear
> currYear
+ 10) {
1498 // we find the closest era that has the given year
1499 // if no era has such given year, we fail the parse
1500 for (CFIndex era
= currEra
-1; era
>= 234; era
--) { // Showa era (234) is the longest era
1501 int32_t years
= __CFDateFormatterGetMaxYearGivenJapaneseEra(cal
, era
, status
);
1502 if (givenYear
> years
) {
1506 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, era
, true, status
);
1509 } else { // current era
1510 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, currEra
, true, status
);
1513 case kCFDateFormatterAmbiguousYearAssumeToNone
:
1515 break; // do nothing
1521 } else { // calenders other than chinese and japanese
1522 int32_t parsedYear
= __cficu_ucal_get(cal
, UCAL_YEAR
, status
);
1523 if (parsedYear
>= 12000 && parsedYear
<= 12099) { // most likely that the parsed string had a 2-digits year
1524 if (formatter
->_property
._TwoDigitStartDate
!= NULL
) {
1525 UCalendar
*tempCal
= __cficu_ucal_clone(cal
, status
);
1526 __cficu_ucal_clear(tempCal
);
1527 CFAbsoluteTime twoDigitAt
= CFDateGetAbsoluteTime(formatter
->_property
._TwoDigitStartDate
);
1528 UDate targetUdate
= (twoDigitAt
+ kCFAbsoluteTimeIntervalSince1970
) * 1000.0;
1529 __cficu_ucal_setMillis(tempCal
, targetUdate
, status
);
1530 int targetYear
= __cficu_ucal_get(tempCal
, UCAL_YEAR
, status
);
1531 parsedYear
-= 12000;
1532 int targetYearM100
= targetYear
% 100;
1533 if (targetYearM100
< parsedYear
) {
1534 parsedYear
= ((targetYear
/ 100) * 100) + parsedYear
;
1535 } else if (parsedYear
< targetYearM100
) {
1536 parsedYear
= ((targetYear
/ 100) * 100) + 100 + parsedYear
;
1538 __cficu_ucal_set(cal
, UCAL_YEAR
, targetYear
);
1539 UDate parseUdate
= __cficu_ucal_getMillis(cal
, status
);
1540 if (parseUdate
>= targetUdate
) {
1541 parsedYear
= targetYear
;
1543 parsedYear
= targetYear
+ 100;
1546 __cficu_ucal_close(tempCal
);
1547 __cficu_ucal_set(cal
, UCAL_YEAR
, parsedYear
);
1548 *at
= __cficu_ucal_getMillis(cal
, status
);
1550 switch (ambigStrat
) {
1551 case kCFDateFormatterAmbiguousYearFailToParse
:
1554 case kCFDateFormatterAmbiguousYearAssumeToCurrent
:
1556 // we can modify cal here because cal is just a temp cal from the caller
1557 __cficu_ucal_setMillis(cal
, __cficu_ucal_getNow(), status
);
1558 int32_t currYear
= __cficu_ucal_get(cal
, UCAL_YEAR
, status
);
1559 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, (currYear
/ 100 * 100) + parsedYear
% 100, false, status
);
1562 case kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate
:
1563 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 100, 50, 49, false, status
);
1565 case kCFDateFormatterAmbiguousYearAssumeToFuture
:
1566 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 100, 0, 99, false, status
);
1568 case kCFDateFormatterAmbiguousYearAssumeToPast
:
1569 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 100, 99, 0, false, status
);
1571 case kCFDateFormatterAmbiguousYearAssumeToLikelyFuture
:
1572 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 100, 9, 90, false, status
);
1574 case kCFDateFormatterAmbiguousYearAssumeToLikelyPast
:
1575 *at
= __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal
, *at
, 100, 90, 9, false, status
);
1577 case kCFDateFormatterAmbiguousYearAssumeToNone
:
1579 if (calendar_id
== kCFCalendarIdentifierGregorian
) { // historical default behavior of 1950 - 2049
1580 int32_t twoDigits
= parsedYear
% 100;
1581 *at
= __CFDateFormatterCorrectTimeWithTarget(cal
, *at
, ((twoDigits
< 50) ? 2000 : 1900) + twoDigits
, false, status
);
1583 break; // do nothing
1592 CFDateRef
CFDateFormatterCreateDateFromString(CFAllocatorRef allocator
, CFDateFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
) {
1593 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
1594 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
1595 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1596 __CFGenericValidateType(string
, CFStringGetTypeID());
1598 if (CFDateFormatterGetAbsoluteTimeFromString(formatter
, string
, rangep
, &at
)) {
1599 return CFDateCreate(allocator
, at
);
1604 Boolean
CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFAbsoluteTime
*atp
) {
1605 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1606 __CFGenericValidateType(string
, CFStringGetTypeID());
1607 CFRange range
= {0, 0};
1611 range
.length
= CFStringGetLength(string
);
1613 if (1024 < range
.length
) range
.length
= 1024;
1614 const UChar
*ustr
= (UChar
*)CFStringGetCharactersPtr(string
);
1615 STACK_BUFFER_DECL(UChar
, ubuffer
, (NULL
== ustr
) ? range
.length
: 1);
1617 CFStringGetCharacters(string
, range
, (UniChar
*)ubuffer
);
1620 ustr
+= range
.location
;
1624 UErrorCode status
= U_ZERO_ERROR
;
1625 UDateFormat
*df2
= __cficu_udat_clone(formatter
->_df
, &status
);
1626 const UCalendar
*ucal2
= __cficu_udat_getCalendar(df2
);
1627 UCalendar
*cal2
= __cficu_ucal_clone(ucal2
, &status
);
1628 CFStringRef calendar_id
= (CFStringRef
) CFDateFormatterCopyProperty(formatter
, kCFDateFormatterCalendarIdentifierKey
);
1629 if (calendar_id
!= kCFCalendarIdentifierChinese
&& calendar_id
!= kCFCalendarIdentifierJapanese
) {
1630 __cficu_ucal_clear(cal2
);
1631 // set both year, and 2DigitYearStart to year 12000
1632 __cficu_ucal_set(cal2
, UCAL_YEAR
, 12000);
1633 __cficu_udat_set2DigitYearStart(df2
, 316516204800.0 * 1000.0, &status
);
1634 } else if (calendar_id
== kCFCalendarIdentifierChinese
) {
1635 __cficu_ucal_clear(cal2
);
1636 __cficu_ucal_set(cal2
, UCAL_ERA
, 1); // default to era 1 if no era info in the string for chinese
1637 } else if (calendar_id
== kCFCalendarIdentifierJapanese
) { // default to the current era
1638 __cficu_ucal_setMillis(cal2
, __cficu_ucal_getNow(), &status
);
1639 int32_t currEra
= __cficu_ucal_get(cal2
, UCAL_ERA
, &status
);
1640 __cficu_ucal_clear(cal2
);
1641 __cficu_ucal_set(cal2
, UCAL_ERA
, currEra
);
1643 if (formatter
->_property
._DefaultDate
) {
1644 CFAbsoluteTime at
= CFDateGetAbsoluteTime(formatter
->_property
._DefaultDate
);
1645 udate
= (at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000.0;
1646 __cficu_ucal_setMillis(cal2
, udate
, &status
);
1648 __cficu_udat_parseCalendar(df2
, cal2
, ustr
, range
.length
, &dpos
, &status
);
1649 udate
= __cficu_ucal_getMillis(cal2
, &status
);
1650 if (rangep
) rangep
->length
= dpos
;
1651 Boolean success
= false;
1652 // first status check is for parsing and the second status check is for the work done inside __CFDateFormatterHandleAmbiguousYear()
1653 if (!U_FAILURE(status
) && (__CFDateFormatterHandleAmbiguousYear(formatter
, calendar_id
, df2
, cal2
, &udate
, ustr
, range
.length
, &status
)) && !U_FAILURE(status
)) {
1655 *atp
= (double)udate
/ 1000.0 - kCFAbsoluteTimeIntervalSince1970
;
1659 CFRelease(calendar_id
);
1660 __cficu_udat_close(df2
);
1661 __cficu_ucal_close(cal2
);
1665 static void __CFDateFormatterSetSymbolsArray(UDateFormat
*icudf
, int32_t icucode
, int index_base
, CFTypeRef value
) {
1666 UErrorCode status
= U_ZERO_ERROR
;
1667 __CFGenericValidateType(value
, CFArrayGetTypeID());
1668 CFArrayRef array
= (CFArrayRef
)value
;
1669 CFIndex idx
, cnt
= CFArrayGetCount(array
);
1670 for (idx
= 0; idx
< cnt
; idx
++) {
1671 CFStringRef item
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
1672 __CFGenericValidateType(item
, CFStringGetTypeID());
1673 CFIndex item_cnt
= CFStringGetLength(item
);
1674 STACK_BUFFER_DECL(UChar
, item_buffer
, __CFMin(BUFFER_SIZE
, item_cnt
));
1675 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr(item
);
1676 if (NULL
== item_ustr
) {
1677 item_cnt
= __CFMin(BUFFER_SIZE
, item_cnt
);
1678 CFStringGetCharacters(item
, CFRangeMake(0, item_cnt
), (UniChar
*)item_buffer
);
1679 item_ustr
= item_buffer
;
1681 status
= U_ZERO_ERROR
;
1682 __cficu_udat_setSymbols(icudf
, (UDateFormatSymbolType
)icucode
, idx
+ index_base
, item_ustr
, item_cnt
, &status
);
1686 static CFArrayRef
__CFDateFormatterGetSymbolsArray(UDateFormat
*icudf
, int32_t icucode
, int index_base
) {
1687 UErrorCode status
= U_ZERO_ERROR
;
1688 CFIndex idx
, cnt
= __cficu_udat_countSymbols(icudf
, (UDateFormatSymbolType
)icucode
);
1689 if (cnt
<= index_base
) return CFArrayCreate(kCFAllocatorSystemDefault
, NULL
, 0, &kCFTypeArrayCallBacks
);
1690 cnt
= cnt
- index_base
;
1691 STACK_BUFFER_DECL(CFStringRef
, strings
, cnt
);
1692 for (idx
= 0; idx
< cnt
; idx
++) {
1693 UChar ubuffer
[BUFFER_SIZE
];
1694 CFStringRef str
= NULL
;
1695 status
= U_ZERO_ERROR
;
1696 CFIndex ucnt
= __cficu_udat_getSymbols(icudf
, (UDateFormatSymbolType
)icucode
, idx
+ index_base
, ubuffer
, BUFFER_SIZE
, &status
);
1697 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1698 str
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, ucnt
);
1700 strings
[idx
] = !str
? (CFStringRef
)CFRetain(CFSTR("<error>")) : str
;
1702 CFArrayRef array
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)strings
, cnt
, &kCFTypeArrayCallBacks
);
1704 CFRelease(strings
[cnt
]);
1709 #define SET_SYMBOLS_ARRAY(A, B, C) \
1710 if (!directToICU) { \
1711 oldProperty = formatter->_property. C; \
1712 formatter->_property. C = NULL; \
1714 __CFDateFormatterSetSymbolsArray(formatter->_df, A, B, value); \
1715 if (!directToICU) { \
1716 formatter->_property. C = __CFDateFormatterGetSymbolsArray(formatter->_df, A, B); \
1719 static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter
, CFStringRef key
, CFTypeRef value
, Boolean directToICU
) {
1720 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1721 __CFGenericValidateType(key
, CFStringGetTypeID());
1722 CFTypeRef oldProperty
= NULL
;
1723 UErrorCode status
= U_ZERO_ERROR
;
1725 if (kCFDateFormatterIsLenientKey
== key
) {
1727 oldProperty
= formatter
->_property
. _IsLenient
;
1728 formatter
->_property
. _IsLenient
= NULL
;
1730 __CFGenericValidateType(value
, CFBooleanGetTypeID());
1732 formatter
->_property
. _IsLenient
= value
? (CFBooleanRef
)CFRetain(value
) : NULL
;
1733 __ResetUDateFormat(formatter
, false);
1735 } else if (kCFDateFormatterDoesRelativeDateFormattingKey
== key
) {
1737 oldProperty
= formatter
->_property
. _DoesRelativeDateFormatting
;
1738 formatter
->_property
. _DoesRelativeDateFormatting
= NULL
;
1740 __CFGenericValidateType(value
, CFBooleanGetTypeID());
1742 if (kCFBooleanTrue
!= value
) value
= kCFBooleanFalse
;
1743 formatter
->_property
. _DoesRelativeDateFormatting
= value
? (CFBooleanRef
)CFRetain(value
) : NULL
;
1744 __ResetUDateFormat(formatter
, false);
1746 } else if (kCFDateFormatterCalendarKey
== key
) {
1748 oldProperty
= formatter
->_property
. _Calendar
;
1749 formatter
->_property
. _Calendar
= NULL
;
1751 __CFGenericValidateType(value
, CFCalendarGetTypeID());
1752 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
1753 CFDictionaryRef components
= CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault
, localeName
);
1754 CFMutableDictionaryRef mcomponents
= CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault
, 0, components
);
1755 CFDictionarySetValue(mcomponents
, kCFLocaleCalendarIdentifierKey
, CFCalendarGetIdentifier((CFCalendarRef
)value
));
1756 localeName
= CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault
, mcomponents
);
1757 CFRelease(mcomponents
);
1758 CFRelease(components
);
1759 CFLocaleRef newLocale
= CFLocaleCreate(CFGetAllocator(formatter
->_locale
), localeName
);
1760 // at this point, we should be setting the preferences if any into this new locale
1761 CFRelease(localeName
);
1762 CFRelease(formatter
->_locale
);
1763 formatter
->_locale
= newLocale
;
1765 formatter
->_property
. _Calendar
= (CFCalendarRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterCalendarKey
);
1766 __ResetUDateFormat(formatter
, false);
1768 } else if (kCFDateFormatterCalendarIdentifierKey
== key
) {
1770 oldProperty
= formatter
->_property
. _CalendarName
;
1771 formatter
->_property
. _CalendarName
= NULL
;
1773 __CFGenericValidateType(value
, CFStringGetTypeID());
1774 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
1775 CFDictionaryRef components
= CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault
, localeName
);
1776 CFMutableDictionaryRef mcomponents
= CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault
, 0, components
);
1777 CFDictionarySetValue(mcomponents
, kCFLocaleCalendarIdentifierKey
, value
);
1778 localeName
= CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault
, mcomponents
);
1779 CFRelease(mcomponents
);
1780 CFRelease(components
);
1781 CFLocaleRef newLocale
= CFLocaleCreate(CFGetAllocator(formatter
->_locale
), localeName
);
1782 // at this point, we should be setting the preferences if any into this new locale
1783 CFRelease(localeName
);
1784 CFRelease(formatter
->_locale
);
1785 formatter
->_locale
= newLocale
;
1787 formatter
->_property
. _CalendarName
= (CFStringRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterCalendarIdentifierKey
);
1788 __ResetUDateFormat(formatter
, false);
1790 } else if (kCFDateFormatterTimeZoneKey
== key
) {
1791 if (formatter
->_property
. _TimeZone
!= value
) {
1793 oldProperty
= formatter
->_property
. _TimeZone
;
1794 formatter
->_property
. _TimeZone
= NULL
;
1796 __CFGenericValidateType(value
, CFTimeZoneGetTypeID());
1797 CFTimeZoneRef old
= formatter
->_property
._TimeZone
;
1798 formatter
->_property
._TimeZone
= value
? (CFTimeZoneRef
)CFRetain(value
) : CFTimeZoneCopyDefault();
1799 if (old
) CFRelease(old
);
1801 old
= formatter
->_property
._TimeZone
;
1802 formatter
->_property
. _TimeZone
= (CFTimeZoneRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterTimeZoneKey
);
1803 __ResetUDateFormat(formatter
, false);
1804 if (old
) CFRelease(old
);
1807 } else if (kCFDateFormatterDefaultFormatKey
== key
) {
1808 // read-only attribute
1809 } else if (kCFDateFormatterTwoDigitStartDateKey
== key
) {
1811 oldProperty
= formatter
->_property
. _TwoDigitStartDate
;
1812 formatter
->_property
. _TwoDigitStartDate
= NULL
;
1814 __CFGenericValidateType(value
, CFDateGetTypeID());
1816 formatter
->_property
. _TwoDigitStartDate
= value
? (CFDateRef
)CFRetain(value
) : NULL
;
1818 } else if (kCFDateFormatterDefaultDateKey
== key
) {
1820 oldProperty
= formatter
->_property
. _DefaultDate
;
1821 formatter
->_property
. _DefaultDate
= NULL
;
1823 __CFGenericValidateType(value
, CFDateGetTypeID());
1825 formatter
->_property
._DefaultDate
= value
? (CFDateRef
)CFRetain(value
) : NULL
;
1827 } else if (kCFDateFormatterGregorianStartDateKey
== key
) {
1829 oldProperty
= formatter
->_property
. _GregorianStartDate
;
1830 formatter
->_property
. _GregorianStartDate
= NULL
;
1832 __CFGenericValidateType(value
, CFDateGetTypeID());
1834 formatter
->_property
. _GregorianStartDate
= value
? (CFDateRef
)CFRetain(value
) : NULL
;
1835 __ResetUDateFormat(formatter
, false);
1837 } else if (kCFDateFormatterEraSymbolsKey
== key
) {
1838 SET_SYMBOLS_ARRAY(UDAT_ERAS
, 0, _EraSymbols
)
1839 } else if (kCFDateFormatterLongEraSymbolsKey
== key
) {
1840 SET_SYMBOLS_ARRAY(UDAT_ERA_NAMES
, 0, _LongEraSymbols
)
1841 } else if (kCFDateFormatterMonthSymbolsKey
== key
) {
1842 SET_SYMBOLS_ARRAY(UDAT_MONTHS
, 0, _MonthSymbols
)
1843 } else if (kCFDateFormatterShortMonthSymbolsKey
== key
) {
1844 SET_SYMBOLS_ARRAY(UDAT_SHORT_MONTHS
, 0, _ShortMonthSymbols
)
1845 } else if (kCFDateFormatterVeryShortMonthSymbolsKey
== key
) {
1846 SET_SYMBOLS_ARRAY(UDAT_NARROW_MONTHS
, 0, _VeryShortMonthSymbols
)
1847 } else if (kCFDateFormatterStandaloneMonthSymbolsKey
== key
) {
1848 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_MONTHS
, 0, _StandaloneMonthSymbols
)
1849 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey
== key
) {
1850 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_MONTHS
, 0, _ShortStandaloneMonthSymbols
)
1851 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey
== key
) {
1852 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_MONTHS
, 0, _VeryShortStandaloneMonthSymbols
)
1853 } else if (kCFDateFormatterWeekdaySymbolsKey
== key
) {
1854 SET_SYMBOLS_ARRAY(UDAT_WEEKDAYS
, 1, _WeekdaySymbols
)
1855 } else if (kCFDateFormatterShortWeekdaySymbolsKey
== key
) {
1856 SET_SYMBOLS_ARRAY(UDAT_SHORT_WEEKDAYS
, 1, _ShortWeekdaySymbols
)
1857 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey
== key
) {
1858 SET_SYMBOLS_ARRAY(UDAT_NARROW_WEEKDAYS
, 1, _VeryShortWeekdaySymbols
)
1859 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey
== key
) {
1860 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_WEEKDAYS
, 1, _StandaloneWeekdaySymbols
)
1861 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey
== key
) {
1862 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_WEEKDAYS
, 1, _ShortStandaloneWeekdaySymbols
)
1863 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey
== key
) {
1864 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_WEEKDAYS
, 1, _VeryShortStandaloneWeekdaySymbols
)
1865 } else if (kCFDateFormatterQuarterSymbolsKey
== key
) {
1866 SET_SYMBOLS_ARRAY(UDAT_QUARTERS
, 0, _QuarterSymbols
)
1867 } else if (kCFDateFormatterShortQuarterSymbolsKey
== key
) {
1868 SET_SYMBOLS_ARRAY(UDAT_SHORT_QUARTERS
, 0, _ShortQuarterSymbols
)
1869 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey
== key
) {
1870 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_QUARTERS
, 0, _StandaloneQuarterSymbols
)
1871 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey
== key
) {
1872 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_QUARTERS
, 0, _ShortStandaloneQuarterSymbols
)
1873 } else if (kCFDateFormatterAMSymbolKey
== key
) {
1875 oldProperty
= formatter
->_property
. _AMSymbol
;
1876 formatter
->_property
. _AMSymbol
= NULL
;
1878 __CFGenericValidateType(value
, CFStringGetTypeID());
1879 CFIndex item_cnt
= CFStringGetLength((CFStringRef
)value
);
1880 STACK_BUFFER_DECL(UChar
, item_buffer
, __CFMin(BUFFER_SIZE
, item_cnt
));
1881 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr((CFStringRef
)value
);
1882 if (NULL
== item_ustr
) {
1883 item_cnt
= __CFMin(BUFFER_SIZE
, item_cnt
);
1884 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, item_cnt
), (UniChar
*)item_buffer
);
1885 item_ustr
= item_buffer
;
1887 __cficu_udat_setSymbols(formatter
->_df
, UDAT_AM_PMS
, 0, item_ustr
, item_cnt
, &status
);
1889 formatter
->_property
. _AMSymbol
= value
? (CFStringRef
)CFStringCreateCopy(NULL
, value
) : NULL
;
1891 } else if (kCFDateFormatterPMSymbolKey
== key
) {
1893 oldProperty
= formatter
->_property
. _PMSymbol
;
1894 formatter
->_property
. _PMSymbol
= NULL
;
1896 __CFGenericValidateType(value
, CFStringGetTypeID());
1897 CFIndex item_cnt
= CFStringGetLength((CFStringRef
)value
);
1898 STACK_BUFFER_DECL(UChar
, item_buffer
, __CFMin(BUFFER_SIZE
, item_cnt
));
1899 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr((CFStringRef
)value
);
1900 if (NULL
== item_ustr
) {
1901 item_cnt
= __CFMin(BUFFER_SIZE
, item_cnt
);
1902 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, item_cnt
), (UniChar
*)item_buffer
);
1903 item_ustr
= item_buffer
;
1905 __cficu_udat_setSymbols(formatter
->_df
, UDAT_AM_PMS
, 1, item_ustr
, item_cnt
, &status
);
1907 formatter
->_property
. _PMSymbol
= value
? (CFStringRef
)CFStringCreateCopy(NULL
, value
) : NULL
;
1909 } else if (kCFDateFormatterAmbiguousYearStrategyKey
== key
) {
1910 oldProperty
= formatter
->_property
._AmbiguousYearStrategy
;
1911 formatter
->_property
._AmbiguousYearStrategy
= NULL
;
1912 __CFGenericValidateType(value
, CFNumberGetTypeID());
1913 formatter
->_property
._AmbiguousYearStrategy
= (CFNumberRef
)CFRetain(value
);
1914 } else if (kCFDateFormatterUsesCharacterDirectionKey
== key
) {
1915 __CFGenericValidateType(value
, CFBooleanGetTypeID());
1916 oldProperty
= formatter
->_property
._UsesCharacterDirection
;
1917 formatter
->_property
._UsesCharacterDirection
= (CFBooleanRef
)CFRetain(value
);
1919 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
1921 if (oldProperty
) CFRelease(oldProperty
);
1924 void CFDateFormatterSetProperty(CFDateFormatterRef formatter
, CFStringRef key
, CFTypeRef value
) {
1925 __CFDateFormatterSetProperty(formatter
, key
, value
, false);
1928 CFTypeRef
CFDateFormatterCopyProperty(CFDateFormatterRef formatter
, CFStringRef key
) {
1929 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1930 __CFGenericValidateType(key
, CFStringGetTypeID());
1931 UErrorCode status
= U_ZERO_ERROR
;
1932 UChar ubuffer
[BUFFER_SIZE
];
1934 if (kCFDateFormatterIsLenientKey
== key
) {
1935 if (formatter
->_property
._IsLenient
) return CFRetain(formatter
->_property
._IsLenient
);
1936 return CFRetain(__cficu_udat_isLenient(formatter
->_df
) ? kCFBooleanTrue
: kCFBooleanFalse
);
1937 } else if (kCFDateFormatterDoesRelativeDateFormattingKey
== key
) {
1938 if (formatter
->_property
._DoesRelativeDateFormatting
) return CFRetain(formatter
->_property
._DoesRelativeDateFormatting
);
1939 return CFRetain(kCFBooleanFalse
);
1940 } else if (kCFDateFormatterCalendarKey
== key
) {
1941 if (formatter
->_property
._Calendar
) return CFRetain(formatter
->_property
._Calendar
);
1942 CFCalendarRef calendar
= (CFCalendarRef
)CFLocaleGetValue(formatter
->_locale
, kCFLocaleCalendarKey
);
1943 return calendar
? CFRetain(calendar
) : NULL
;
1944 } else if (kCFDateFormatterCalendarIdentifierKey
== key
) {
1945 if (formatter
->_property
._CalendarName
) return CFRetain(formatter
->_property
._CalendarName
);
1946 CFStringRef ident
= (CFStringRef
)CFLocaleGetValue(formatter
->_locale
, kCFLocaleCalendarIdentifierKey
);
1947 return ident
? CFRetain(ident
) : NULL
;
1948 } else if (kCFDateFormatterTimeZoneKey
== key
) {
1949 return formatter
->_property
._TimeZone
? CFRetain(formatter
->_property
._TimeZone
) : NULL
;
1950 } else if (kCFDateFormatterDefaultFormatKey
== key
) {
1951 return formatter
->_defformat
? CFRetain(formatter
->_defformat
) : NULL
;
1952 } else if (kCFDateFormatterTwoDigitStartDateKey
== key
) {
1953 return formatter
->_property
._TwoDigitStartDate
? CFRetain(formatter
->_property
._TwoDigitStartDate
) : NULL
;
1954 } else if (kCFDateFormatterDefaultDateKey
== key
) {
1955 return formatter
->_property
._DefaultDate
? CFRetain(formatter
->_property
._DefaultDate
) : NULL
;
1956 } else if (kCFDateFormatterGregorianStartDateKey
== key
) {
1957 if (formatter
->_property
._GregorianStartDate
) return CFRetain(formatter
->_property
._GregorianStartDate
);
1958 const UCalendar
*cal
= __cficu_udat_getCalendar(formatter
->_df
);
1959 UDate udate
= __cficu_ucal_getGregorianChange(cal
, &status
);
1960 if (U_SUCCESS(status
)) {
1961 CFAbsoluteTime at
= (double)udate
/ 1000.0 - kCFAbsoluteTimeIntervalSince1970
;
1962 return CFDateCreate(CFGetAllocator(formatter
), at
);
1964 } else if (kCFDateFormatterEraSymbolsKey
== key
) {
1965 if (formatter
->_property
._EraSymbols
) return CFRetain(formatter
->_property
._EraSymbols
);
1966 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_ERAS
, 0);
1967 } else if (kCFDateFormatterLongEraSymbolsKey
== key
) {
1968 if (formatter
->_property
._LongEraSymbols
) return CFRetain(formatter
->_property
._LongEraSymbols
);
1969 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_ERA_NAMES
, 0);
1970 } else if (kCFDateFormatterMonthSymbolsKey
== key
) {
1971 if (formatter
->_property
._MonthSymbols
) return CFRetain(formatter
->_property
._MonthSymbols
);
1972 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_MONTHS
, 0);
1973 } else if (kCFDateFormatterShortMonthSymbolsKey
== key
) {
1974 if (formatter
->_property
._ShortMonthSymbols
) return CFRetain(formatter
->_property
._ShortMonthSymbols
);
1975 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_SHORT_MONTHS
, 0);
1976 } else if (kCFDateFormatterVeryShortMonthSymbolsKey
== key
) {
1977 if (formatter
->_property
._VeryShortMonthSymbols
) return CFRetain(formatter
->_property
._VeryShortMonthSymbols
);
1978 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_NARROW_MONTHS
, 0);
1979 } else if (kCFDateFormatterStandaloneMonthSymbolsKey
== key
) {
1980 if (formatter
->_property
._StandaloneMonthSymbols
) return CFRetain(formatter
->_property
._StandaloneMonthSymbols
);
1981 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_MONTHS
, 0);
1982 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey
== key
) {
1983 if (formatter
->_property
._ShortStandaloneMonthSymbols
) return CFRetain(formatter
->_property
._ShortStandaloneMonthSymbols
);
1984 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_SHORT_MONTHS
, 0);
1985 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey
== key
) {
1986 if (formatter
->_property
._VeryShortStandaloneMonthSymbols
) return CFRetain(formatter
->_property
._VeryShortStandaloneMonthSymbols
);
1987 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_NARROW_MONTHS
, 0);
1988 } else if (kCFDateFormatterWeekdaySymbolsKey
== key
) {
1989 if (formatter
->_property
._WeekdaySymbols
) return CFRetain(formatter
->_property
._WeekdaySymbols
);
1990 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_WEEKDAYS
, 1);
1991 } else if (kCFDateFormatterShortWeekdaySymbolsKey
== key
) {
1992 if (formatter
->_property
._ShortWeekdaySymbols
) return CFRetain(formatter
->_property
._ShortWeekdaySymbols
);
1993 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_SHORT_WEEKDAYS
, 1);
1994 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey
== key
) {
1995 if (formatter
->_property
._VeryShortWeekdaySymbols
) return CFRetain(formatter
->_property
._VeryShortWeekdaySymbols
);
1996 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_NARROW_WEEKDAYS
, 1);
1997 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey
== key
) {
1998 if (formatter
->_property
._StandaloneWeekdaySymbols
) return CFRetain(formatter
->_property
._StandaloneWeekdaySymbols
);
1999 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_WEEKDAYS
, 1);
2000 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey
== key
) {
2001 if (formatter
->_property
._ShortStandaloneWeekdaySymbols
) return CFRetain(formatter
->_property
._ShortStandaloneWeekdaySymbols
);
2002 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_SHORT_WEEKDAYS
, 1);
2003 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey
== key
) {
2004 if (formatter
->_property
._VeryShortStandaloneWeekdaySymbols
) return CFRetain(formatter
->_property
._VeryShortStandaloneWeekdaySymbols
);
2005 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_NARROW_WEEKDAYS
, 1);
2006 } else if (kCFDateFormatterQuarterSymbolsKey
== key
) {
2007 if (formatter
->_property
._QuarterSymbols
) return CFRetain(formatter
->_property
._QuarterSymbols
);
2008 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_QUARTERS
, 0);
2009 } else if (kCFDateFormatterShortQuarterSymbolsKey
== key
) {
2010 if (formatter
->_property
._ShortQuarterSymbols
) return CFRetain(formatter
->_property
._ShortQuarterSymbols
);
2011 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_SHORT_QUARTERS
, 0);
2012 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey
== key
) {
2013 if (formatter
->_property
._StandaloneQuarterSymbols
) return CFRetain(formatter
->_property
._StandaloneQuarterSymbols
);
2014 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_QUARTERS
, 0);
2015 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey
== key
) {
2016 if (formatter
->_property
._ShortStandaloneQuarterSymbols
) return CFRetain(formatter
->_property
._ShortStandaloneQuarterSymbols
);
2017 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_SHORT_QUARTERS
, 0);
2018 } else if (kCFDateFormatterAMSymbolKey
== key
) {
2019 if (formatter
->_property
._AMSymbol
) return CFRetain(formatter
->_property
._AMSymbol
);
2020 CFIndex cnt
= __cficu_udat_countSymbols(formatter
->_df
, UDAT_AM_PMS
);
2022 CFIndex ucnt
= __cficu_udat_getSymbols(formatter
->_df
, UDAT_AM_PMS
, 0, ubuffer
, BUFFER_SIZE
, &status
);
2023 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
2024 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (UniChar
*)ubuffer
, ucnt
);
2027 } else if (kCFDateFormatterPMSymbolKey
== key
) {
2028 if (formatter
->_property
._PMSymbol
) return CFRetain(formatter
->_property
._PMSymbol
);
2029 CFIndex cnt
= __cficu_udat_countSymbols(formatter
->_df
, UDAT_AM_PMS
);
2031 CFIndex ucnt
= __cficu_udat_getSymbols(formatter
->_df
, UDAT_AM_PMS
, 1, ubuffer
, BUFFER_SIZE
, &status
);
2032 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
2033 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (UniChar
*)ubuffer
, ucnt
);
2036 } else if (kCFDateFormatterAmbiguousYearStrategyKey
== key
) {
2037 if (formatter
->_property
._AmbiguousYearStrategy
) return CFRetain(formatter
->_property
._AmbiguousYearStrategy
);
2038 } else if (kCFDateFormatterUsesCharacterDirectionKey
== key
) {
2039 return formatter
->_property
._UsesCharacterDirection
? CFRetain(formatter
->_property
._UsesCharacterDirection
) : CFRetain(kCFBooleanFalse
);
2041 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);