2 * Copyright (c) 2012 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-2011, 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 <unicode/udat.h>
40 #include <unicode/udatpg.h>
44 extern UCalendar
*__CFCalendarCreateUCalendar(CFStringRef calendarID
, CFStringRef localeID
, CFTimeZoneRef tz
);
45 static void __CFDateFormatterCustomize(CFDateFormatterRef formatter
);
47 CF_EXPORT
const CFStringRef kCFDateFormatterCalendarIdentifierKey
;
49 #undef CFReleaseIfNotNull
50 #define CFReleaseIfNotNull(X) if (X) CFRelease(X)
52 #define BUFFER_SIZE 768
54 static CFStringRef
__CFDateFormatterCreateForcedTemplate(CFLocaleRef locale
, CFStringRef inString
);
56 // If you pass in a string in tmplate, you get back NULL (failure) or a CFStringRef.
57 // 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.
59 CFArrayRef
CFDateFormatterCreateDateFormatsFromTemplates(CFAllocatorRef allocator
, CFArrayRef tmplates
, CFOptionFlags options
, CFLocaleRef locale
) {
60 return (CFArrayRef
)CFDateFormatterCreateDateFormatFromTemplate(allocator
, (CFStringRef
)tmplates
, options
, locale
);
63 CFStringRef
CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator
, CFStringRef tmplate
, CFOptionFlags options
, CFLocaleRef locale
) {
64 if (allocator
) __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
65 if (locale
) __CFGenericValidateType(locale
, CFLocaleGetTypeID());
66 Boolean tmplateIsString
= (CFStringGetTypeID() == CFGetTypeID(tmplate
));
67 if (!tmplateIsString
) {
68 __CFGenericValidateType(tmplate
, CFArrayGetTypeID());
71 CFStringRef localeName
= locale
? CFLocaleGetIdentifier(locale
) : CFSTR("");
72 char buffer
[BUFFER_SIZE
];
73 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
75 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
81 UErrorCode status
= U_ZERO_ERROR
;
82 UDateTimePatternGenerator
*ptg
= udatpg_open(cstr
, &status
);
83 if (NULL
== ptg
|| U_FAILURE(status
)) {
87 CFTypeRef result
= tmplateIsString
? NULL
: (CFTypeRef
)CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
89 for (CFIndex idx
= 0, cnt
= tmplateIsString
? 1 : CFArrayGetCount((CFArrayRef
)tmplate
); idx
< cnt
; idx
++) {
90 CFStringRef tmplateString
= tmplateIsString
? (CFStringRef
)tmplate
: (CFStringRef
)CFArrayGetValueAtIndex((CFArrayRef
)tmplate
, idx
);
91 CFStringRef resultString
= NULL
;
93 tmplateString
= __CFDateFormatterCreateForcedTemplate(locale
? locale
: CFLocaleGetSystem(), tmplateString
);
95 CFIndex jCount
= 0; // the only interesting cases are 0, 1, and 2 (adjacent)
96 CFRange r
= CFStringFind(tmplateString
, CFSTR("j"), 0);
97 if (kCFNotFound
!= r
.location
) {
99 if ((r
.location
+ 1 < CFStringGetLength(tmplateString
)) && ('j' == CFStringGetCharacterAtIndex(tmplateString
, r
.location
+ 1))) {
104 UChar pattern
[BUFFER_SIZE
], skel
[BUFFER_SIZE
], bpat
[BUFFER_SIZE
];
105 CFIndex tmpltLen
= CFStringGetLength(tmplateString
);
106 if (BUFFER_SIZE
< tmpltLen
) tmpltLen
= BUFFER_SIZE
;
107 CFStringGetCharacters(tmplateString
, CFRangeMake(0, tmpltLen
), (UniChar
*)pattern
);
108 CFRelease(tmplateString
);
110 int32_t patlen
= tmpltLen
;
111 status
= U_ZERO_ERROR
;
112 int32_t skellen
= udatpg_getSkeleton(ptg
, pattern
, patlen
, skel
, sizeof(skel
) / sizeof(skel
[0]), &status
);
113 if (!U_FAILURE(status
)) {
114 if ((0 < jCount
) && (skellen
+ jCount
< (sizeof(skel
) / sizeof(skel
[0])))) {
115 skel
[skellen
++] = 'j';
116 if (1 < jCount
) skel
[skellen
++] = 'j';
119 status
= U_ZERO_ERROR
;
120 int32_t bpatlen
= udatpg_getBestPattern(ptg
, skel
, skellen
, bpat
, sizeof(bpat
) / sizeof(bpat
[0]), &status
);
121 if (!U_FAILURE(status
)) {
122 resultString
= CFStringCreateWithCharacters(allocator
, (const UniChar
*)bpat
, bpatlen
);
126 if (tmplateIsString
) {
127 result
= (CFTypeRef
)resultString
;
129 CFArrayAppendValue((CFMutableArrayRef
)result
, resultString
? (CFTypeRef
)resultString
: (CFTypeRef
)kCFNull
);
130 if (resultString
) CFRelease(resultString
);
136 return (CFStringRef
)result
;
139 struct __CFDateFormatter
{
143 CFDateFormatterStyle _timeStyle
;
144 CFDateFormatterStyle _dateStyle
;
146 CFStringRef _defformat
;
148 CFBooleanRef _IsLenient
;
149 CFBooleanRef _DoesRelativeDateFormatting
;
150 CFBooleanRef _HasCustomFormat
;
151 CFTimeZoneRef _TimeZone
;
152 CFCalendarRef _Calendar
;
153 CFStringRef _CalendarName
;
154 CFDateRef _TwoDigitStartDate
;
155 CFDateRef _DefaultDate
;
156 CFDateRef _GregorianStartDate
;
157 CFArrayRef _EraSymbols
;
158 CFArrayRef _LongEraSymbols
;
159 CFArrayRef _MonthSymbols
;
160 CFArrayRef _ShortMonthSymbols
;
161 CFArrayRef _VeryShortMonthSymbols
;
162 CFArrayRef _StandaloneMonthSymbols
;
163 CFArrayRef _ShortStandaloneMonthSymbols
;
164 CFArrayRef _VeryShortStandaloneMonthSymbols
;
165 CFArrayRef _WeekdaySymbols
;
166 CFArrayRef _ShortWeekdaySymbols
;
167 CFArrayRef _VeryShortWeekdaySymbols
;
168 CFArrayRef _StandaloneWeekdaySymbols
;
169 CFArrayRef _ShortStandaloneWeekdaySymbols
;
170 CFArrayRef _VeryShortStandaloneWeekdaySymbols
;
171 CFArrayRef _QuarterSymbols
;
172 CFArrayRef _ShortQuarterSymbols
;
173 CFArrayRef _StandaloneQuarterSymbols
;
174 CFArrayRef _ShortStandaloneQuarterSymbols
;
175 CFStringRef _AMSymbol
;
176 CFStringRef _PMSymbol
;
180 static CFStringRef
__CFDateFormatterCopyDescription(CFTypeRef cf
) {
181 CFDateFormatterRef formatter
= (CFDateFormatterRef
)cf
;
182 return CFStringCreateWithFormat(CFGetAllocator(formatter
), NULL
, CFSTR("<CFDateFormatter %p [%p]>"), cf
, CFGetAllocator(formatter
));
185 static void __CFDateFormatterDeallocate(CFTypeRef cf
) {
186 CFDateFormatterRef formatter
= (CFDateFormatterRef
)cf
;
187 if (formatter
->_df
) udat_close(formatter
->_df
);
188 if (formatter
->_locale
) CFRelease(formatter
->_locale
);
189 if (formatter
->_format
) CFRelease(formatter
->_format
);
190 if (formatter
->_defformat
) CFRelease(formatter
->_defformat
);
191 CFReleaseIfNotNull(formatter
->_property
._IsLenient
);
192 CFReleaseIfNotNull(formatter
->_property
._DoesRelativeDateFormatting
);
193 CFReleaseIfNotNull(formatter
->_property
._TimeZone
);
194 CFReleaseIfNotNull(formatter
->_property
._Calendar
);
195 CFReleaseIfNotNull(formatter
->_property
._CalendarName
);
196 CFReleaseIfNotNull(formatter
->_property
._TwoDigitStartDate
);
197 CFReleaseIfNotNull(formatter
->_property
._DefaultDate
);
198 CFReleaseIfNotNull(formatter
->_property
._GregorianStartDate
);
199 CFReleaseIfNotNull(formatter
->_property
._EraSymbols
);
200 CFReleaseIfNotNull(formatter
->_property
._LongEraSymbols
);
201 CFReleaseIfNotNull(formatter
->_property
._MonthSymbols
);
202 CFReleaseIfNotNull(formatter
->_property
._ShortMonthSymbols
);
203 CFReleaseIfNotNull(formatter
->_property
._VeryShortMonthSymbols
);
204 CFReleaseIfNotNull(formatter
->_property
._StandaloneMonthSymbols
);
205 CFReleaseIfNotNull(formatter
->_property
._ShortStandaloneMonthSymbols
);
206 CFReleaseIfNotNull(formatter
->_property
._VeryShortStandaloneMonthSymbols
);
207 CFReleaseIfNotNull(formatter
->_property
._WeekdaySymbols
);
208 CFReleaseIfNotNull(formatter
->_property
._ShortWeekdaySymbols
);
209 CFReleaseIfNotNull(formatter
->_property
._VeryShortWeekdaySymbols
);
210 CFReleaseIfNotNull(formatter
->_property
._StandaloneWeekdaySymbols
);
211 CFReleaseIfNotNull(formatter
->_property
._ShortStandaloneWeekdaySymbols
);
212 CFReleaseIfNotNull(formatter
->_property
._VeryShortStandaloneWeekdaySymbols
);
213 CFReleaseIfNotNull(formatter
->_property
._QuarterSymbols
);
214 CFReleaseIfNotNull(formatter
->_property
._ShortQuarterSymbols
);
215 CFReleaseIfNotNull(formatter
->_property
._StandaloneQuarterSymbols
);
216 CFReleaseIfNotNull(formatter
->_property
._ShortStandaloneQuarterSymbols
);
217 CFReleaseIfNotNull(formatter
->_property
._AMSymbol
);
218 CFReleaseIfNotNull(formatter
->_property
._PMSymbol
);
221 static CFStringRef
__CFDateFormatterCreateForcedString(CFDateFormatterRef formatter
, CFStringRef inString
);
223 static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter
, CFStringRef key
, CFTypeRef value
, Boolean directToICU
);
225 #define RESET_PROPERTY(C, K) \
226 if (df->_property. C) __CFDateFormatterSetProperty(df, K, df->_property. C, true);
228 // This blows away any custom format string the client may have set
229 // on the date formatter with CFDateFormatterSetFormat().
230 static void __ResetUDateFormat(CFDateFormatterRef df
, Boolean goingToHaveCustomFormat
) {
231 if (df
->_df
) udat_close(df
->_df
);
234 // uses _timeStyle, _dateStyle, _locale, _property._TimeZone; sets _df, _format, _defformat
235 char loc_buffer
[BUFFER_SIZE
];
237 CFStringRef tmpLocName
= df
->_locale
? CFLocaleGetIdentifier(df
->_locale
) : CFSTR("");
238 CFStringGetCString(tmpLocName
, loc_buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
);
240 UChar tz_buffer
[BUFFER_SIZE
];
242 CFStringRef tmpTZName
= df
->_property
._TimeZone
? CFTimeZoneGetName(df
->_property
._TimeZone
) : CFSTR("GMT");
243 CFStringGetCharacters(tmpTZName
, CFRangeMake(0, CFStringGetLength(tmpTZName
)), (UniChar
*)tz_buffer
);
245 df
->_property
._HasCustomFormat
= NULL
;
247 int32_t udstyle
= 0, utstyle
= 0;
248 switch (df
->_dateStyle
) {
249 case kCFDateFormatterNoStyle
: udstyle
= UDAT_NONE
; break;
250 case kCFDateFormatterShortStyle
: udstyle
= UDAT_SHORT
; break;
251 case kCFDateFormatterMediumStyle
: udstyle
= UDAT_MEDIUM
; break;
252 case kCFDateFormatterLongStyle
: udstyle
= UDAT_LONG
; break;
253 case kCFDateFormatterFullStyle
: udstyle
= UDAT_FULL
; break;
255 switch (df
->_timeStyle
) {
256 case kCFDateFormatterNoStyle
: utstyle
= UDAT_NONE
; break;
257 case kCFDateFormatterShortStyle
: utstyle
= UDAT_SHORT
; break;
258 case kCFDateFormatterMediumStyle
: utstyle
= UDAT_MEDIUM
; break;
259 case kCFDateFormatterLongStyle
: utstyle
= UDAT_LONG
; break;
260 case kCFDateFormatterFullStyle
: utstyle
= UDAT_FULL
; break;
262 Boolean wantRelative
= (NULL
!= df
->_property
._DoesRelativeDateFormatting
&& df
->_property
._DoesRelativeDateFormatting
== kCFBooleanTrue
);
263 Boolean hasFormat
= (NULL
!= df
->_property
._HasCustomFormat
&& df
->_property
._HasCustomFormat
== kCFBooleanTrue
) || goingToHaveCustomFormat
;
264 if (wantRelative
&& !hasFormat
) {
265 udstyle
|= UDAT_RELATIVE
;
268 UErrorCode status
= U_ZERO_ERROR
;
269 UDateFormat
*icudf
= udat_open((UDateFormatStyle
)utstyle
, (UDateFormatStyle
)udstyle
, loc_buffer
, tz_buffer
, CFStringGetLength(tmpTZName
), NULL
, 0, &status
);
270 if (NULL
== icudf
|| U_FAILURE(status
)) {
273 udat_setLenient(icudf
, 0);
274 if (kCFDateFormatterNoStyle
== df
->_dateStyle
&& kCFDateFormatterNoStyle
== df
->_timeStyle
) {
275 udat_applyPattern(icudf
, false, NULL
, 0);
277 CFStringRef calident
= (CFStringRef
)CFLocaleGetValue(df
->_locale
, kCFLocaleCalendarIdentifierKey
);
278 if (calident
&& CFEqual(calident
, kCFCalendarIdentifierGregorian
)) {
279 status
= U_ZERO_ERROR
;
280 udat_set2DigitYearStart(icudf
, -631152000000.0, &status
); // 1950-01-01 00:00:00 GMT
284 __CFDateFormatterCustomize(df
);
286 UChar ubuffer
[BUFFER_SIZE
];
287 status
= U_ZERO_ERROR
;
288 int32_t ret
= udat_toPattern(icudf
, false, ubuffer
, BUFFER_SIZE
, &status
);
289 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
290 CFStringRef newFormat
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, ret
);
291 CFStringRef formatString
= __CFDateFormatterCreateForcedString(df
, newFormat
);
292 CFIndex cnt
= CFStringGetLength(formatString
);
293 CFAssert1(cnt
<= 1024, __kCFLogAssertion
, "%s(): format string too long", __PRETTY_FUNCTION__
);
294 if (df
->_format
!= formatString
&& cnt
<= 1024) {
295 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
296 const UChar
*ustr
= (UChar
*)CFStringGetCharactersPtr((CFStringRef
)formatString
);
298 CFStringGetCharacters(formatString
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
301 UErrorCode status
= U_ZERO_ERROR
;
302 // udat_applyPattern(df->_df, false, ustr, cnt, &status);
303 udat_applyPattern(df
->_df
, false, ustr
, cnt
);
304 if (U_SUCCESS(status
)) {
305 if (df
->_format
) CFRelease(df
->_format
);
306 df
->_format
= (CFStringRef
)CFStringCreateCopy(CFGetAllocator(df
), formatString
);
309 CFRelease(formatString
);
310 CFRelease(newFormat
);
312 if (df
->_defformat
) CFRelease(df
->_defformat
);
313 df
->_defformat
= df
->_format
? (CFStringRef
)CFRetain(df
->_format
) : NULL
;
315 RESET_PROPERTY(_IsLenient
, kCFDateFormatterIsLenientKey
);
316 RESET_PROPERTY(_DoesRelativeDateFormatting
, kCFDateFormatterDoesRelativeDateFormattingKey
);
317 RESET_PROPERTY(_Calendar
, kCFDateFormatterCalendarKey
);
318 RESET_PROPERTY(_CalendarName
, kCFDateFormatterCalendarIdentifierKey
);
319 RESET_PROPERTY(_TimeZone
, kCFDateFormatterTimeZoneKey
);
320 RESET_PROPERTY(_TwoDigitStartDate
, kCFDateFormatterTwoDigitStartDateKey
);
321 RESET_PROPERTY(_DefaultDate
, kCFDateFormatterDefaultDateKey
);
322 RESET_PROPERTY(_GregorianStartDate
, kCFDateFormatterGregorianStartDateKey
);
323 RESET_PROPERTY(_EraSymbols
, kCFDateFormatterEraSymbolsKey
);
324 RESET_PROPERTY(_LongEraSymbols
, kCFDateFormatterLongEraSymbolsKey
);
325 RESET_PROPERTY(_MonthSymbols
, kCFDateFormatterMonthSymbolsKey
);
326 RESET_PROPERTY(_ShortMonthSymbols
, kCFDateFormatterShortMonthSymbolsKey
);
327 RESET_PROPERTY(_VeryShortMonthSymbols
, kCFDateFormatterVeryShortMonthSymbolsKey
);
328 RESET_PROPERTY(_StandaloneMonthSymbols
, kCFDateFormatterStandaloneMonthSymbolsKey
);
329 RESET_PROPERTY(_ShortStandaloneMonthSymbols
, kCFDateFormatterShortStandaloneMonthSymbolsKey
);
330 RESET_PROPERTY(_VeryShortStandaloneMonthSymbols
, kCFDateFormatterVeryShortStandaloneMonthSymbolsKey
);
331 RESET_PROPERTY(_WeekdaySymbols
, kCFDateFormatterWeekdaySymbolsKey
);
332 RESET_PROPERTY(_ShortWeekdaySymbols
, kCFDateFormatterShortWeekdaySymbolsKey
);
333 RESET_PROPERTY(_VeryShortWeekdaySymbols
, kCFDateFormatterVeryShortWeekdaySymbolsKey
);
334 RESET_PROPERTY(_StandaloneWeekdaySymbols
, kCFDateFormatterStandaloneWeekdaySymbolsKey
);
335 RESET_PROPERTY(_ShortStandaloneWeekdaySymbols
, kCFDateFormatterShortStandaloneWeekdaySymbolsKey
);
336 RESET_PROPERTY(_VeryShortStandaloneWeekdaySymbols
, kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey
);
337 RESET_PROPERTY(_QuarterSymbols
, kCFDateFormatterQuarterSymbolsKey
);
338 RESET_PROPERTY(_ShortQuarterSymbols
, kCFDateFormatterShortQuarterSymbolsKey
);
339 RESET_PROPERTY(_StandaloneQuarterSymbols
, kCFDateFormatterStandaloneQuarterSymbolsKey
);
340 RESET_PROPERTY(_ShortStandaloneQuarterSymbols
, kCFDateFormatterShortStandaloneQuarterSymbolsKey
);
341 RESET_PROPERTY(_AMSymbol
, kCFDateFormatterAMSymbolKey
);
342 RESET_PROPERTY(_PMSymbol
, kCFDateFormatterPMSymbolKey
);
345 static CFTypeID __kCFDateFormatterTypeID
= _kCFRuntimeNotATypeID
;
347 static const CFRuntimeClass __CFDateFormatterClass
= {
352 __CFDateFormatterDeallocate
,
356 __CFDateFormatterCopyDescription
359 static void __CFDateFormatterInitialize(void) {
360 __kCFDateFormatterTypeID
= _CFRuntimeRegisterClass(&__CFDateFormatterClass
);
363 CFTypeID
CFDateFormatterGetTypeID(void) {
364 if (_kCFRuntimeNotATypeID
== __kCFDateFormatterTypeID
) __CFDateFormatterInitialize();
365 return __kCFDateFormatterTypeID
;
368 CFDateFormatterRef
CFDateFormatterCreate(CFAllocatorRef allocator
, CFLocaleRef locale
, CFDateFormatterStyle dateStyle
, CFDateFormatterStyle timeStyle
) {
369 struct __CFDateFormatter
*memory
;
370 uint32_t size
= sizeof(struct __CFDateFormatter
) - sizeof(CFRuntimeBase
);
371 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
372 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
373 if (locale
) __CFGenericValidateType(locale
, CFLocaleGetTypeID());
374 memory
= (struct __CFDateFormatter
*)_CFRuntimeCreateInstance(allocator
, CFDateFormatterGetTypeID(), size
, NULL
);
375 if (NULL
== memory
) {
379 memory
->_locale
= NULL
;
380 memory
->_format
= NULL
;
381 memory
->_defformat
= NULL
;
382 memory
->_dateStyle
= dateStyle
;
383 memory
->_timeStyle
= timeStyle
;
384 memory
->_property
._IsLenient
= NULL
;
385 memory
->_property
._DoesRelativeDateFormatting
= NULL
;
386 memory
->_property
._HasCustomFormat
= NULL
;
387 memory
->_property
._TimeZone
= NULL
;
388 memory
->_property
._Calendar
= NULL
;
389 memory
->_property
._CalendarName
= NULL
;
390 memory
->_property
._TwoDigitStartDate
= NULL
;
391 memory
->_property
._DefaultDate
= NULL
;
392 memory
->_property
._GregorianStartDate
= NULL
;
393 memory
->_property
._EraSymbols
= NULL
;
394 memory
->_property
._LongEraSymbols
= NULL
;
395 memory
->_property
._MonthSymbols
= NULL
;
396 memory
->_property
._ShortMonthSymbols
= NULL
;
397 memory
->_property
._VeryShortMonthSymbols
= NULL
;
398 memory
->_property
._StandaloneMonthSymbols
= NULL
;
399 memory
->_property
._ShortStandaloneMonthSymbols
= NULL
;
400 memory
->_property
._VeryShortStandaloneMonthSymbols
= NULL
;
401 memory
->_property
._WeekdaySymbols
= NULL
;
402 memory
->_property
._ShortWeekdaySymbols
= NULL
;
403 memory
->_property
._VeryShortWeekdaySymbols
= NULL
;
404 memory
->_property
._StandaloneWeekdaySymbols
= NULL
;
405 memory
->_property
._ShortStandaloneWeekdaySymbols
= NULL
;
406 memory
->_property
._VeryShortStandaloneWeekdaySymbols
= NULL
;
407 memory
->_property
._QuarterSymbols
= NULL
;
408 memory
->_property
._ShortQuarterSymbols
= NULL
;
409 memory
->_property
._StandaloneQuarterSymbols
= NULL
;
410 memory
->_property
._ShortStandaloneQuarterSymbols
= NULL
;
411 memory
->_property
._AMSymbol
= NULL
;
412 memory
->_property
._PMSymbol
= NULL
;
415 case kCFDateFormatterNoStyle
:
416 case kCFDateFormatterShortStyle
:
417 case kCFDateFormatterMediumStyle
:
418 case kCFDateFormatterLongStyle
:
419 case kCFDateFormatterFullStyle
: break;
421 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown date style %d", __PRETTY_FUNCTION__
, dateStyle
);
422 memory
->_dateStyle
= kCFDateFormatterMediumStyle
;
426 case kCFDateFormatterNoStyle
:
427 case kCFDateFormatterShortStyle
:
428 case kCFDateFormatterMediumStyle
:
429 case kCFDateFormatterLongStyle
:
430 case kCFDateFormatterFullStyle
: break;
432 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown time style %d", __PRETTY_FUNCTION__
, timeStyle
);
433 memory
->_timeStyle
= kCFDateFormatterMediumStyle
;
437 memory
->_locale
= locale
? CFLocaleCreateCopy(allocator
, locale
) : (CFLocaleRef
)CFRetain(CFLocaleGetSystem());
438 memory
->_property
._TimeZone
= CFTimeZoneCopyDefault();
439 __ResetUDateFormat(memory
, false);
444 return (CFDateFormatterRef
)memory
;
447 extern CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
);
449 static void __substituteFormatStringFromPrefsDFRelative(CFDateFormatterRef formatter
) {
450 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
452 CFIndex dateLen
= -1;
453 UChar dateBuffer
[BUFFER_SIZE
];
454 if (kCFDateFormatterNoStyle
!= formatter
->_dateStyle
) {
455 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUDateFormatStrings")) : NULL
;
456 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
458 switch (formatter
->_dateStyle
) {
459 case kCFDateFormatterShortStyle
: key
= CFSTR("1"); break;
460 case kCFDateFormatterMediumStyle
: key
= CFSTR("2"); break;
461 case kCFDateFormatterLongStyle
: key
= CFSTR("3"); break;
462 case kCFDateFormatterFullStyle
: key
= CFSTR("4"); break;
463 default: key
= CFSTR("0"); break;
465 CFStringRef pref
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
466 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFStringGetTypeID()) {
467 dateLen
= __CFMin(CFStringGetLength(pref
), BUFFER_SIZE
);
468 CFStringGetCharacters(pref
, CFRangeMake(0, dateLen
), (UniChar
*)dateBuffer
);
473 UErrorCode status
= U_ZERO_ERROR
;
474 int32_t ret
= udat_toPatternRelativeDate(formatter
->_df
, dateBuffer
, BUFFER_SIZE
, &status
);
475 if (!U_FAILURE(status
)) {
480 CFIndex timeLen
= -1;
481 UChar timeBuffer
[BUFFER_SIZE
];
482 if (kCFDateFormatterNoStyle
!= formatter
->_timeStyle
) {
483 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUTimeFormatStrings")) : NULL
;
484 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
486 switch (formatter
->_timeStyle
) {
487 case kCFDateFormatterShortStyle
: key
= CFSTR("1"); break;
488 case kCFDateFormatterMediumStyle
: key
= CFSTR("2"); break;
489 case kCFDateFormatterLongStyle
: key
= CFSTR("3"); break;
490 case kCFDateFormatterFullStyle
: key
= CFSTR("4"); break;
491 default: key
= CFSTR("0"); break;
493 CFStringRef pref
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
494 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFStringGetTypeID()) {
495 timeLen
= __CFMin(CFStringGetLength(pref
), BUFFER_SIZE
);
496 CFStringGetCharacters(pref
, CFRangeMake(0, timeLen
), (UniChar
*)timeBuffer
);
501 UErrorCode status
= U_ZERO_ERROR
;
502 int32_t ret
= udat_toPatternRelativeTime(formatter
->_df
, timeBuffer
, BUFFER_SIZE
, &status
);
503 if (!U_FAILURE(status
)) {
508 UErrorCode status
= U_ZERO_ERROR
;
509 udat_applyPatternRelative(formatter
->_df
, (0 <= dateLen
) ? dateBuffer
: NULL
, (0 <= dateLen
) ? dateLen
: 0, (0 <= timeLen
) ? timeBuffer
: NULL
, (0 <= timeLen
) ? timeLen
: 0, &status
);
512 static void __substituteFormatStringFromPrefsDF(CFDateFormatterRef formatter
, bool doTime
) {
513 CFIndex formatStyle
= doTime
? formatter
->_timeStyle
: formatter
->_dateStyle
;
514 CFStringRef prefName
= doTime
? CFSTR("AppleICUTimeFormatStrings") : CFSTR("AppleICUDateFormatStrings");
515 if (kCFDateFormatterNoStyle
!= formatStyle
) {
516 CFStringRef pref
= NULL
;
517 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
518 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, prefName
) : NULL
;
519 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
521 switch (formatStyle
) {
522 case kCFDateFormatterShortStyle
: key
= CFSTR("1"); break;
523 case kCFDateFormatterMediumStyle
: key
= CFSTR("2"); break;
524 case kCFDateFormatterLongStyle
: key
= CFSTR("3"); break;
525 case kCFDateFormatterFullStyle
: key
= CFSTR("4"); break;
526 default: key
= CFSTR("0"); break;
528 pref
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
530 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFStringGetTypeID()) {
531 int32_t icustyle
= UDAT_NONE
;
532 switch (formatStyle
) {
533 case kCFDateFormatterShortStyle
: icustyle
= UDAT_SHORT
; break;
534 case kCFDateFormatterMediumStyle
: icustyle
= UDAT_MEDIUM
; break;
535 case kCFDateFormatterLongStyle
: icustyle
= UDAT_LONG
; break;
536 case kCFDateFormatterFullStyle
: icustyle
= UDAT_FULL
; break;
538 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
539 char buffer
[BUFFER_SIZE
];
540 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
542 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
544 UErrorCode status
= U_ZERO_ERROR
;
545 UDateFormat
*df
= udat_open((UDateFormatStyle
)(doTime
? icustyle
: UDAT_NONE
), (UDateFormatStyle
)(doTime
? UDAT_NONE
: icustyle
), cstr
, NULL
, 0, NULL
, 0, &status
);
547 UChar ubuffer
[BUFFER_SIZE
];
548 status
= U_ZERO_ERROR
;
549 int32_t date_len
= udat_toPattern(df
, false, ubuffer
, BUFFER_SIZE
, &status
);
550 if (U_SUCCESS(status
) && date_len
<= BUFFER_SIZE
) {
551 CFStringRef dateString
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)ubuffer
, date_len
);
552 status
= U_ZERO_ERROR
;
553 int32_t formatter_len
= udat_toPattern(formatter
->_df
, false, ubuffer
, BUFFER_SIZE
, &status
);
554 if (U_SUCCESS(status
) && formatter_len
<= BUFFER_SIZE
) {
555 CFMutableStringRef formatString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
556 CFStringAppendCharacters(formatString
, (UniChar
*)ubuffer
, formatter_len
);
557 // find dateString inside formatString, substitute the pref in that range
559 if (CFStringFindWithOptions(formatString
, dateString
, CFRangeMake(0, formatter_len
), 0, &result
)) {
560 CFStringReplace(formatString
, result
, pref
);
561 int32_t new_len
= CFStringGetLength(formatString
);
562 STACK_BUFFER_DECL(UChar
, new_buffer
, new_len
);
563 const UChar
*new_ustr
= (UChar
*)CFStringGetCharactersPtr(formatString
);
564 if (NULL
== new_ustr
) {
565 CFStringGetCharacters(formatString
, CFRangeMake(0, new_len
), (UniChar
*)new_buffer
);
566 new_ustr
= new_buffer
;
568 status
= U_ZERO_ERROR
;
569 // udat_applyPattern(formatter->_df, false, new_ustr, new_len, &status);
570 udat_applyPattern(formatter
->_df
, false, new_ustr
, new_len
);
572 CFRelease(formatString
);
574 CFRelease(dateString
);
582 static void __CFDateFormatterApplySymbolPrefs(const void *key
, const void *value
, void *context
) {
583 if (CFGetTypeID(key
) == CFStringGetTypeID() && CFGetTypeID(value
) == CFArrayGetTypeID()) {
584 CFDateFormatterRef formatter
= (CFDateFormatterRef
)context
;
585 UDateFormatSymbolType sym
= (UDateFormatSymbolType
)CFStringGetIntValue((CFStringRef
)key
);
586 CFArrayRef array
= (CFArrayRef
)value
;
587 CFIndex idx
, cnt
= CFArrayGetCount(array
);
588 for (idx
= 0; idx
< cnt
; idx
++) {
589 CFStringRef item
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
590 if (CFGetTypeID(item
) != CFStringGetTypeID()) continue;
591 CFIndex item_cnt
= CFStringGetLength(item
);
592 STACK_BUFFER_DECL(UChar
, item_buffer
, __CFMin(BUFFER_SIZE
, item_cnt
));
593 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr(item
);
594 if (NULL
== item_ustr
) {
595 item_cnt
= __CFMin(BUFFER_SIZE
, item_cnt
);
596 CFStringGetCharacters(item
, CFRangeMake(0, item_cnt
), (UniChar
*)item_buffer
);
597 item_ustr
= item_buffer
;
599 UErrorCode status
= U_ZERO_ERROR
;
600 udat_setSymbols(formatter
->_df
, sym
, idx
, item_ustr
, item_cnt
, &status
);
605 static CFStringRef
__CFDateFormatterCreateForcedTemplate(CFLocaleRef locale
, CFStringRef inString
) {
606 if (!inString
) return NULL
;
608 Boolean doForce24
= false, doForce12
= false;
609 CFDictionaryRef prefs
= __CFLocaleGetPrefs(locale
);
610 CFPropertyListRef pref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUForce24HourTime")) : NULL
;
611 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFBooleanGetTypeID()) {
612 doForce24
= CFBooleanGetValue((CFBooleanRef
)pref
);
614 pref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUForce12HourTime")) : NULL
;
615 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFBooleanGetTypeID()) {
616 doForce12
= CFBooleanGetValue((CFBooleanRef
)pref
);
618 if (doForce24
) doForce12
= false; // if both are set, Force24 wins, period
619 if (!doForce24
&& !doForce12
) return (CFStringRef
)CFRetain(inString
);
621 CFMutableStringRef outString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
622 CFIndex cnt
= CFStringGetLength(inString
);
623 CFIndex lastSecond
= -1, lastMinute
= -1, firstHour
= -1;
624 Boolean isInQuote
= false, hasA
= false, had12Hour
= false, had24Hour
= false;
625 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
627 UniChar ch
= CFStringGetCharacterAtIndex(inString
, idx
);
629 case '\'': isInQuote
= !isInQuote
; break;
630 case 'j': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); if (doForce24
) ch
= 'H'; else ch
= 'h';} break;
631 case 'h': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had12Hour
= true; if (doForce24
) ch
= 'H';} break; // switch 12-hour to 24-hour
632 case 'K': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had12Hour
= true; if (doForce24
) ch
= 'k';} break; // switch 12-hour to 24-hour
633 case 'H': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had24Hour
= true; if (doForce12
) ch
= 'h';} break; // switch 24-hour to 12-hour
634 case 'k': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had24Hour
= true; if (doForce12
) ch
= 'K';} break; // switch 24-hour to 12-hour
635 case 'm': if (!isInQuote
) lastMinute
= CFStringGetLength(outString
); break;
636 case 's': if (!isInQuote
) lastSecond
= CFStringGetLength(outString
); break;
637 case 'a': if (!isInQuote
) {hasA
= true; if (doForce24
) emit
= false;} break;
640 if (emit
) CFStringAppendCharacters(outString
, &ch
, 1);
646 static CFStringRef
__CFDateFormatterCreateForcedString(CFDateFormatterRef formatter
, CFStringRef inString
) {
647 if (!inString
) return NULL
;
649 Boolean doForce24
= false, doForce12
= false;
650 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
651 CFPropertyListRef pref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUForce24HourTime")) : NULL
;
652 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFBooleanGetTypeID()) {
653 doForce24
= CFBooleanGetValue((CFBooleanRef
)pref
);
655 pref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUForce12HourTime")) : NULL
;
656 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFBooleanGetTypeID()) {
657 doForce12
= CFBooleanGetValue((CFBooleanRef
)pref
);
659 if (doForce24
) doForce12
= false; // if both are set, Force24 wins, period
660 if (!doForce24
&& !doForce12
) return (CFStringRef
)CFRetain(inString
);
662 CFMutableStringRef outString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
663 CFIndex cnt
= CFStringGetLength(inString
);
664 CFIndex lastSecond
= -1, lastMinute
= -1, firstHour
= -1;
665 Boolean isInQuote
= false, hasA
= false, had12Hour
= false, had24Hour
= false;
666 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
668 UniChar ch
= CFStringGetCharacterAtIndex(inString
, idx
);
670 case '\'': isInQuote
= !isInQuote
; break;
671 case 'h': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had12Hour
= true; if (doForce24
) ch
= 'H';} break; // switch 12-hour to 24-hour
672 case 'K': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had12Hour
= true; if (doForce24
) ch
= 'k';} break; // switch 12-hour to 24-hour
673 case 'H': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had24Hour
= true; if (doForce12
) ch
= 'h';} break; // switch 24-hour to 12-hour
674 case 'k': if (!isInQuote
) {if (-1 == firstHour
) firstHour
= CFStringGetLength(outString
); had24Hour
= true; if (doForce12
) ch
= 'K';} break; // switch 24-hour to 12-hour
675 case 'm': if (!isInQuote
) lastMinute
= CFStringGetLength(outString
); break;
676 case 's': if (!isInQuote
) lastSecond
= CFStringGetLength(outString
); break;
677 case 'a': if (!isInQuote
) hasA
= true;
678 if (!isInQuote
&& doForce24
) {
679 // skip 'a' and one optional trailing space
681 if (idx
+ 1 < cnt
&& ' ' == CFStringGetCharacterAtIndex(inString
, idx
+ 1)) idx
++;
685 if (!isInQuote
&& doForce24
) {
686 // if next character is 'a' AND we have seen the hour designator, skip space and 'a'
687 if (idx
+ 1 < cnt
&& 'a' == CFStringGetCharacterAtIndex(inString
, idx
+ 1) && -1 != firstHour
) {
694 if (emit
) CFStringAppendCharacters(outString
, &ch
, 1);
696 if (doForce12
&& !hasA
&& had24Hour
) {
697 CFStringRef locName
= CFLocaleGetIdentifier(formatter
->_locale
);
698 if (-1 != firstHour
&& (CFStringHasPrefix(locName
, CFSTR("ko")) || CFEqual(locName
, CFSTR("zh_SG")))) {
699 CFStringInsert(outString
, firstHour
, CFSTR("a "));
700 } else if (-1 != firstHour
&& (CFStringHasPrefix(locName
, CFSTR("zh")) || CFStringHasPrefix(locName
, CFSTR("ja")))) {
701 CFStringInsert(outString
, firstHour
, CFSTR("a"));
703 CFIndex lastPos
= (-1 != lastSecond
) ? lastSecond
: ((-1 != lastMinute
) ? lastMinute
: -1);
705 cnt
= CFStringGetLength(outString
);
707 UniChar ch
= (lastPos
< cnt
) ? CFStringGetCharacterAtIndex(outString
, lastPos
) : 0;
709 case '\"': lastPos
++; break;
714 ch
= (lastPos
< cnt
) ? CFStringGetCharacterAtIndex(outString
, lastPos
) : 0;
715 } while ('\'' != ch
&& '\0' != ch
);
716 if ('\'' == ch
) lastPos
++;
717 ch
= (lastPos
< cnt
) ? CFStringGetCharacterAtIndex(outString
, lastPos
) : 0;
718 if ('\'' == ch
) goto again
;
721 CFStringInsert(outString
, lastPos
, CFSTR(" a"));
728 static void __CFDateFormatterCustomize(CFDateFormatterRef formatter
) {
729 Boolean wantRelative
= (NULL
!= formatter
->_property
._DoesRelativeDateFormatting
&& formatter
->_property
._DoesRelativeDateFormatting
== kCFBooleanTrue
);
730 Boolean hasFormat
= (NULL
!= formatter
->_property
._HasCustomFormat
&& formatter
->_property
._HasCustomFormat
== kCFBooleanTrue
);
731 if (wantRelative
&& !hasFormat
) {
732 __substituteFormatStringFromPrefsDFRelative(formatter
);
734 __substituteFormatStringFromPrefsDF(formatter
, false);
735 __substituteFormatStringFromPrefsDF(formatter
, true);
737 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
738 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUDateTimeSymbols")) : NULL
;
739 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
740 CFDictionaryApplyFunction((CFDictionaryRef
)metapref
, __CFDateFormatterApplySymbolPrefs
, formatter
);
742 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleFirstWeekday")) : NULL
;
743 CFStringRef calID
= (CFStringRef
)CFLocaleGetValue(formatter
->_locale
, kCFLocaleCalendarIdentifierKey
);
744 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
745 metapref
= (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, calID
);
747 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFNumberGetTypeID()) {
749 if (CFNumberGetValue((CFNumberRef
)metapref
, kCFNumberCFIndexType
, &wkdy
)) {
750 UCalendar
*cal
= (UCalendar
*)udat_getCalendar(formatter
->_df
);
751 if (cal
) ucal_setAttribute(cal
, UCAL_FIRST_DAY_OF_WEEK
, wkdy
);
754 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleMinDaysInFirstWeek")) : NULL
;
755 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
756 metapref
= (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, calID
);
758 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFNumberGetTypeID()) {
760 if (CFNumberGetValue((CFNumberRef
)metapref
, kCFNumberCFIndexType
, &mwd
)) {
761 UCalendar
*cal
= (UCalendar
*)udat_getCalendar(formatter
->_df
);
762 if (cal
) ucal_setAttribute(cal
, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
, mwd
);
767 CFLocaleRef
CFDateFormatterGetLocale(CFDateFormatterRef formatter
) {
768 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
769 return formatter
->_locale
;
772 CFDateFormatterStyle
CFDateFormatterGetDateStyle(CFDateFormatterRef formatter
) {
773 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
774 return formatter
->_dateStyle
;
777 CFDateFormatterStyle
CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter
) {
778 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
779 return formatter
->_timeStyle
;
782 CFStringRef
CFDateFormatterGetFormat(CFDateFormatterRef formatter
) {
783 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
784 return formatter
->_format
;
787 void CFDateFormatterSetFormat(CFDateFormatterRef formatter
, CFStringRef formatString
) {
788 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
789 __CFGenericValidateType(formatString
, CFStringGetTypeID());
790 formatString
= __CFDateFormatterCreateForcedString(formatter
, formatString
);
791 CFIndex cnt
= CFStringGetLength(formatString
);
792 CFAssert1(cnt
<= 1024, __kCFLogAssertion
, "%s(): format string too long", __PRETTY_FUNCTION__
);
793 if (formatter
->_format
!= formatString
&& cnt
<= 1024) {
794 // When going from a situation where there is no custom format already,
795 // and the "relative date formatting" property is set, we need to reset
796 // the whole UDateFormat.
797 if (formatter
->_property
._HasCustomFormat
!= kCFBooleanTrue
&& formatter
->_property
._DoesRelativeDateFormatting
== kCFBooleanTrue
) {
798 __ResetUDateFormat(formatter
, true);
800 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
801 const UChar
*ustr
= (UChar
*)CFStringGetCharactersPtr((CFStringRef
)formatString
);
803 CFStringGetCharacters(formatString
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
806 UErrorCode status
= U_ZERO_ERROR
;
807 // udat_applyPattern(formatter->_df, false, ustr, cnt, &status);
808 udat_applyPattern(formatter
->_df
, false, ustr
, cnt
);
809 if (U_SUCCESS(status
)) {
810 if (formatter
->_format
) CFRelease(formatter
->_format
);
811 formatter
->_format
= (CFStringRef
)CFStringCreateCopy(CFGetAllocator(formatter
), formatString
);
812 formatter
->_property
._HasCustomFormat
= kCFBooleanTrue
;
815 if (formatString
) CFRelease(formatString
);
818 CFStringRef
CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator
, CFDateFormatterRef formatter
, CFDateRef date
) {
819 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
820 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
821 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
822 __CFGenericValidateType(date
, CFDateGetTypeID());
823 return CFDateFormatterCreateStringWithAbsoluteTime(allocator
, formatter
, CFDateGetAbsoluteTime(date
));
826 CFStringRef
CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator
, CFDateFormatterRef formatter
, CFAbsoluteTime at
) {
827 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
828 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
829 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
830 UChar
*ustr
= NULL
, ubuffer
[BUFFER_SIZE
];
831 UErrorCode status
= U_ZERO_ERROR
;
832 CFIndex used
, cnt
= BUFFER_SIZE
;
833 UDate ud
= (at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000.0 + 0.5;
834 used
= udat_format(formatter
->_df
, ud
, ubuffer
, cnt
, NULL
, &status
);
835 if (status
== U_BUFFER_OVERFLOW_ERROR
|| cnt
< used
) {
837 ustr
= (UChar
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(UChar
) * cnt
, 0);
838 status
= U_ZERO_ERROR
;
839 used
= udat_format(formatter
->_df
, ud
, ustr
, cnt
, NULL
, &status
);
841 CFStringRef string
= NULL
;
842 if (U_SUCCESS(status
)) {
843 string
= CFStringCreateWithCharacters(allocator
, (const UniChar
*)(ustr
? ustr
: ubuffer
), used
);
845 if (ustr
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, ustr
);
849 CFDateRef
CFDateFormatterCreateDateFromString(CFAllocatorRef allocator
, CFDateFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
) {
850 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
851 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
852 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
853 __CFGenericValidateType(string
, CFStringGetTypeID());
855 if (CFDateFormatterGetAbsoluteTimeFromString(formatter
, string
, rangep
, &at
)) {
856 return CFDateCreate(allocator
, at
);
861 Boolean
CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFAbsoluteTime
*atp
) {
862 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
863 __CFGenericValidateType(string
, CFStringGetTypeID());
864 CFRange range
= {0, 0};
868 range
.length
= CFStringGetLength(string
);
870 if (1024 < range
.length
) range
.length
= 1024;
871 const UChar
*ustr
= (UChar
*)CFStringGetCharactersPtr(string
);
872 STACK_BUFFER_DECL(UChar
, ubuffer
, (NULL
== ustr
) ? range
.length
: 1);
874 CFStringGetCharacters(string
, range
, (UniChar
*)ubuffer
);
877 ustr
+= range
.location
;
881 UErrorCode status
= U_ZERO_ERROR
;
882 if (formatter
->_property
._DefaultDate
) {
883 CFAbsoluteTime at
= CFDateGetAbsoluteTime(formatter
->_property
._DefaultDate
);
884 udate
= (at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000.0;
885 UDateFormat
*df2
= udat_clone(formatter
->_df
, &status
);
886 UCalendar
*cal2
= (UCalendar
*)udat_getCalendar(df2
);
887 ucal_setMillis(cal2
, udate
, &status
);
888 udat_parseCalendar(formatter
->_df
, cal2
, ustr
, range
.length
, &dpos
, &status
);
889 udate
= ucal_getMillis(cal2
, &status
);
892 udate
= udat_parse(formatter
->_df
, ustr
, range
.length
, &dpos
, &status
);
894 if (rangep
) rangep
->length
= dpos
;
895 if (U_FAILURE(status
)) {
899 *atp
= (double)udate
/ 1000.0 - kCFAbsoluteTimeIntervalSince1970
;
904 static void __CFDateFormatterSetSymbolsArray(UDateFormat
*icudf
, int32_t icucode
, int index_base
, CFTypeRef value
) {
905 UErrorCode status
= U_ZERO_ERROR
;
906 __CFGenericValidateType(value
, CFArrayGetTypeID());
907 CFArrayRef array
= (CFArrayRef
)value
;
908 CFIndex idx
, cnt
= CFArrayGetCount(array
);
909 for (idx
= 0; idx
< cnt
; idx
++) {
910 CFStringRef item
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
911 __CFGenericValidateType(item
, CFStringGetTypeID());
912 CFIndex item_cnt
= CFStringGetLength(item
);
913 STACK_BUFFER_DECL(UChar
, item_buffer
, __CFMin(BUFFER_SIZE
, item_cnt
));
914 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr(item
);
915 if (NULL
== item_ustr
) {
916 item_cnt
= __CFMin(BUFFER_SIZE
, item_cnt
);
917 CFStringGetCharacters(item
, CFRangeMake(0, item_cnt
), (UniChar
*)item_buffer
);
918 item_ustr
= item_buffer
;
920 status
= U_ZERO_ERROR
;
921 udat_setSymbols(icudf
, (UDateFormatSymbolType
)icucode
, idx
+ index_base
, item_ustr
, item_cnt
, &status
);
925 static CFArrayRef
__CFDateFormatterGetSymbolsArray(UDateFormat
*icudf
, int32_t icucode
, int index_base
) {
926 UErrorCode status
= U_ZERO_ERROR
;
927 CFIndex idx
, cnt
= udat_countSymbols(icudf
, (UDateFormatSymbolType
)icucode
);
928 if (cnt
<= index_base
) return CFArrayCreate(kCFAllocatorSystemDefault
, NULL
, 0, &kCFTypeArrayCallBacks
);
929 cnt
= cnt
- index_base
;
930 STACK_BUFFER_DECL(CFStringRef
, strings
, cnt
);
931 for (idx
= 0; idx
< cnt
; idx
++) {
932 UChar ubuffer
[BUFFER_SIZE
];
933 CFStringRef str
= NULL
;
934 status
= U_ZERO_ERROR
;
935 CFIndex ucnt
= udat_getSymbols(icudf
, (UDateFormatSymbolType
)icucode
, idx
+ index_base
, ubuffer
, BUFFER_SIZE
, &status
);
936 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
937 str
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, ucnt
);
939 strings
[idx
] = !str
? (CFStringRef
)CFRetain(CFSTR("<error>")) : str
;
941 CFArrayRef array
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)strings
, cnt
, &kCFTypeArrayCallBacks
);
943 CFRelease(strings
[cnt
]);
948 #define SET_SYMBOLS_ARRAY(A, B, C) \
949 if (!directToICU) { \
950 oldProperty = formatter->_property. C; \
951 formatter->_property. C = NULL; \
953 __CFDateFormatterSetSymbolsArray(formatter->_df, A, B, value); \
954 if (!directToICU) { \
955 formatter->_property. C = __CFDateFormatterGetSymbolsArray(formatter->_df, A, B); \
958 static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter
, CFStringRef key
, CFTypeRef value
, Boolean directToICU
) {
959 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
960 __CFGenericValidateType(key
, CFStringGetTypeID());
961 CFTypeRef oldProperty
= NULL
;
962 UErrorCode status
= U_ZERO_ERROR
;
963 UChar ubuffer
[BUFFER_SIZE
];
965 if (kCFDateFormatterIsLenientKey
== key
) {
967 oldProperty
= formatter
->_property
. _IsLenient
;
968 formatter
->_property
. _IsLenient
= NULL
;
970 __CFGenericValidateType(value
, CFBooleanGetTypeID());
971 udat_setLenient(formatter
->_df
, (kCFBooleanTrue
== value
));
972 UCalendar
*cal
= (UCalendar
*)udat_getCalendar(formatter
->_df
);
973 if (cal
) ucal_setAttribute(cal
, UCAL_LENIENT
, (kCFBooleanTrue
== value
));
975 formatter
->_property
. _IsLenient
= (CFBooleanRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterIsLenientKey
);
977 } else if (kCFDateFormatterDoesRelativeDateFormattingKey
== key
) {
979 oldProperty
= formatter
->_property
. _DoesRelativeDateFormatting
;
980 formatter
->_property
. _DoesRelativeDateFormatting
= NULL
;
982 __CFGenericValidateType(value
, CFBooleanGetTypeID());
984 if (kCFBooleanTrue
!= value
) value
= kCFBooleanFalse
;
985 formatter
->_property
. _DoesRelativeDateFormatting
= value
? (CFBooleanRef
)CFRetain(value
) : NULL
;
986 __ResetUDateFormat(formatter
, false);
988 } else if (kCFDateFormatterCalendarKey
== key
) {
990 oldProperty
= formatter
->_property
. _Calendar
;
991 formatter
->_property
. _Calendar
= NULL
;
993 __CFGenericValidateType(value
, CFCalendarGetTypeID());
994 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
995 CFDictionaryRef components
= CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault
, localeName
);
996 CFMutableDictionaryRef mcomponents
= CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault
, 0, components
);
997 CFDictionarySetValue(mcomponents
, kCFLocaleCalendarIdentifierKey
, CFCalendarGetIdentifier((CFCalendarRef
)value
));
998 localeName
= CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault
, mcomponents
);
999 CFRelease(mcomponents
);
1000 CFRelease(components
);
1001 CFLocaleRef newLocale
= CFLocaleCreate(CFGetAllocator(formatter
->_locale
), localeName
);
1002 CFRelease(localeName
);
1003 CFRelease(formatter
->_locale
);
1004 formatter
->_locale
= newLocale
;
1005 UCalendar
*cal
= __CFCalendarCreateUCalendar(NULL
, CFLocaleGetIdentifier(formatter
->_locale
), formatter
->_property
._TimeZone
);
1006 if (cal
) ucal_setAttribute(cal
, UCAL_FIRST_DAY_OF_WEEK
, CFCalendarGetFirstWeekday((CFCalendarRef
)value
));
1007 if (cal
) ucal_setAttribute(cal
, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
, CFCalendarGetMinimumDaysInFirstWeek((CFCalendarRef
)value
));
1008 if (cal
) udat_setCalendar(formatter
->_df
, cal
);
1009 if (cal
) ucal_close(cal
);
1011 formatter
->_property
. _Calendar
= (CFCalendarRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterCalendarKey
);
1013 } else if (kCFDateFormatterCalendarIdentifierKey
== key
) {
1015 oldProperty
= formatter
->_property
. _CalendarName
;
1016 formatter
->_property
. _CalendarName
= NULL
;
1018 __CFGenericValidateType(value
, CFStringGetTypeID());
1019 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
1020 CFDictionaryRef components
= CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault
, localeName
);
1021 CFMutableDictionaryRef mcomponents
= CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault
, 0, components
);
1022 CFDictionarySetValue(mcomponents
, kCFLocaleCalendarIdentifierKey
, value
);
1023 localeName
= CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault
, mcomponents
);
1024 CFRelease(mcomponents
);
1025 CFRelease(components
);
1026 CFLocaleRef newLocale
= CFLocaleCreate(CFGetAllocator(formatter
->_locale
), localeName
);
1027 CFRelease(localeName
);
1028 CFRelease(formatter
->_locale
);
1029 formatter
->_locale
= newLocale
;
1030 UCalendar
*cal
= __CFCalendarCreateUCalendar(NULL
, CFLocaleGetIdentifier(formatter
->_locale
), formatter
->_property
._TimeZone
);
1031 if (cal
) udat_setCalendar(formatter
->_df
, cal
);
1032 if (cal
) ucal_close(cal
);
1034 formatter
->_property
. _CalendarName
= (CFStringRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterCalendarIdentifierKey
);
1036 } else if (kCFDateFormatterTimeZoneKey
== key
) {
1037 if (formatter
->_property
. _TimeZone
!= value
) {
1039 oldProperty
= formatter
->_property
. _TimeZone
;
1040 formatter
->_property
. _TimeZone
= NULL
;
1042 __CFGenericValidateType(value
, CFTimeZoneGetTypeID());
1043 CFTimeZoneRef old
= formatter
->_property
._TimeZone
;
1044 formatter
->_property
._TimeZone
= value
? (CFTimeZoneRef
)CFRetain(value
) : CFTimeZoneCopyDefault();
1045 if (old
) CFRelease(old
);
1046 CFStringRef tznam
= CFTimeZoneGetName(formatter
->_property
._TimeZone
);
1047 UCalendar
*cal
= (UCalendar
*)udat_getCalendar(formatter
->_df
);
1048 CFIndex ucnt
= CFStringGetLength(tznam
);
1049 if (BUFFER_SIZE
< ucnt
) ucnt
= BUFFER_SIZE
;
1050 CFStringGetCharacters(tznam
, CFRangeMake(0, ucnt
), (UniChar
*)ubuffer
);
1051 ucal_setTimeZone(cal
, ubuffer
, ucnt
, &status
);
1053 old
= formatter
->_property
._TimeZone
;
1054 formatter
->_property
. _TimeZone
= (CFTimeZoneRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterTimeZoneKey
);
1055 if (old
) CFRelease(old
);
1058 } else if (kCFDateFormatterDefaultFormatKey
== key
) {
1059 // read-only attribute
1060 } else if (kCFDateFormatterTwoDigitStartDateKey
== key
) {
1062 oldProperty
= formatter
->_property
. _TwoDigitStartDate
;
1063 formatter
->_property
. _TwoDigitStartDate
= NULL
;
1065 __CFGenericValidateType(value
, CFDateGetTypeID());
1066 CFAbsoluteTime at
= CFDateGetAbsoluteTime((CFDateRef
)value
);
1067 UDate udate
= (at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000.0;
1068 udat_set2DigitYearStart(formatter
->_df
, udate
, &status
);
1070 formatter
->_property
. _TwoDigitStartDate
= (CFDateRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterTwoDigitStartDateKey
);
1072 } else if (kCFDateFormatterDefaultDateKey
== key
) {
1074 oldProperty
= formatter
->_property
. _DefaultDate
;
1075 formatter
->_property
. _DefaultDate
= NULL
;
1077 __CFGenericValidateType(value
, CFDateGetTypeID());
1079 formatter
->_property
._DefaultDate
= value
? (CFDateRef
)CFRetain(value
) : NULL
;
1081 } else if (kCFDateFormatterGregorianStartDateKey
== key
) {
1083 oldProperty
= formatter
->_property
. _GregorianStartDate
;
1084 formatter
->_property
. _GregorianStartDate
= NULL
;
1086 __CFGenericValidateType(value
, CFDateGetTypeID());
1087 CFAbsoluteTime at
= CFDateGetAbsoluteTime((CFDateRef
)value
);
1088 UDate udate
= (at
+ kCFAbsoluteTimeIntervalSince1970
) * 1000.0;
1089 UCalendar
*cal
= (UCalendar
*)udat_getCalendar(formatter
->_df
);
1090 ucal_setGregorianChange(cal
, udate
, &status
);
1092 formatter
->_property
. _GregorianStartDate
= (CFDateRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterGregorianStartDateKey
);
1094 } else if (kCFDateFormatterEraSymbolsKey
== key
) {
1095 SET_SYMBOLS_ARRAY(UDAT_ERAS
, 0, _EraSymbols
)
1096 } else if (kCFDateFormatterLongEraSymbolsKey
== key
) {
1097 SET_SYMBOLS_ARRAY(UDAT_ERA_NAMES
, 0, _LongEraSymbols
)
1098 } else if (kCFDateFormatterMonthSymbolsKey
== key
) {
1099 SET_SYMBOLS_ARRAY(UDAT_MONTHS
, 0, _MonthSymbols
)
1100 } else if (kCFDateFormatterShortMonthSymbolsKey
== key
) {
1101 SET_SYMBOLS_ARRAY(UDAT_SHORT_MONTHS
, 0, _ShortMonthSymbols
)
1102 } else if (kCFDateFormatterVeryShortMonthSymbolsKey
== key
) {
1103 SET_SYMBOLS_ARRAY(UDAT_NARROW_MONTHS
, 0, _VeryShortMonthSymbols
)
1104 } else if (kCFDateFormatterStandaloneMonthSymbolsKey
== key
) {
1105 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_MONTHS
, 0, _StandaloneMonthSymbols
)
1106 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey
== key
) {
1107 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_MONTHS
, 0, _ShortStandaloneMonthSymbols
)
1108 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey
== key
) {
1109 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_MONTHS
, 0, _VeryShortStandaloneMonthSymbols
)
1110 } else if (kCFDateFormatterWeekdaySymbolsKey
== key
) {
1111 SET_SYMBOLS_ARRAY(UDAT_WEEKDAYS
, 1, _WeekdaySymbols
)
1112 } else if (kCFDateFormatterShortWeekdaySymbolsKey
== key
) {
1113 SET_SYMBOLS_ARRAY(UDAT_SHORT_WEEKDAYS
, 1, _ShortWeekdaySymbols
)
1114 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey
== key
) {
1115 SET_SYMBOLS_ARRAY(UDAT_NARROW_WEEKDAYS
, 1, _VeryShortWeekdaySymbols
)
1116 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey
== key
) {
1117 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_WEEKDAYS
, 1, _StandaloneWeekdaySymbols
)
1118 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey
== key
) {
1119 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_WEEKDAYS
, 1, _ShortStandaloneWeekdaySymbols
)
1120 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey
== key
) {
1121 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_WEEKDAYS
, 1, _VeryShortStandaloneWeekdaySymbols
)
1122 } else if (kCFDateFormatterQuarterSymbolsKey
== key
) {
1123 SET_SYMBOLS_ARRAY(UDAT_QUARTERS
, 0, _QuarterSymbols
)
1124 } else if (kCFDateFormatterShortQuarterSymbolsKey
== key
) {
1125 SET_SYMBOLS_ARRAY(UDAT_SHORT_QUARTERS
, 0, _ShortQuarterSymbols
)
1126 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey
== key
) {
1127 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_QUARTERS
, 0, _StandaloneQuarterSymbols
)
1128 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey
== key
) {
1129 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_QUARTERS
, 0, _ShortStandaloneQuarterSymbols
)
1130 } else if (kCFDateFormatterAMSymbolKey
== key
) {
1132 oldProperty
= formatter
->_property
. _AMSymbol
;
1133 formatter
->_property
. _AMSymbol
= NULL
;
1135 __CFGenericValidateType(value
, CFStringGetTypeID());
1136 CFIndex item_cnt
= CFStringGetLength((CFStringRef
)value
);
1137 STACK_BUFFER_DECL(UChar
, item_buffer
, __CFMin(BUFFER_SIZE
, item_cnt
));
1138 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr((CFStringRef
)value
);
1139 if (NULL
== item_ustr
) {
1140 item_cnt
= __CFMin(BUFFER_SIZE
, item_cnt
);
1141 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, item_cnt
), (UniChar
*)item_buffer
);
1142 item_ustr
= item_buffer
;
1144 udat_setSymbols(formatter
->_df
, UDAT_AM_PMS
, 0, item_ustr
, item_cnt
, &status
);
1146 formatter
->_property
. _AMSymbol
= (CFStringRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterAMSymbolKey
);
1148 } else if (kCFDateFormatterPMSymbolKey
== key
) {
1150 oldProperty
= formatter
->_property
. _PMSymbol
;
1151 formatter
->_property
. _PMSymbol
= NULL
;
1153 __CFGenericValidateType(value
, CFStringGetTypeID());
1154 CFIndex item_cnt
= CFStringGetLength((CFStringRef
)value
);
1155 STACK_BUFFER_DECL(UChar
, item_buffer
, __CFMin(BUFFER_SIZE
, item_cnt
));
1156 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr((CFStringRef
)value
);
1157 if (NULL
== item_ustr
) {
1158 item_cnt
= __CFMin(BUFFER_SIZE
, item_cnt
);
1159 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, item_cnt
), (UniChar
*)item_buffer
);
1160 item_ustr
= item_buffer
;
1162 udat_setSymbols(formatter
->_df
, UDAT_AM_PMS
, 1, item_ustr
, item_cnt
, &status
);
1164 formatter
->_property
. _PMSymbol
= (CFStringRef
)CFDateFormatterCopyProperty(formatter
, kCFDateFormatterPMSymbolKey
);
1167 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
1169 if (oldProperty
) CFRelease(oldProperty
);
1172 void CFDateFormatterSetProperty(CFDateFormatterRef formatter
, CFStringRef key
, CFTypeRef value
) {
1173 __CFDateFormatterSetProperty(formatter
, key
, value
, false);
1176 CFTypeRef
CFDateFormatterCopyProperty(CFDateFormatterRef formatter
, CFStringRef key
) {
1177 __CFGenericValidateType(formatter
, CFDateFormatterGetTypeID());
1178 __CFGenericValidateType(key
, CFStringGetTypeID());
1179 UErrorCode status
= U_ZERO_ERROR
;
1180 UChar ubuffer
[BUFFER_SIZE
];
1182 if (kCFDateFormatterIsLenientKey
== key
) {
1183 if (formatter
->_property
._IsLenient
) return CFRetain(formatter
->_property
._IsLenient
);
1184 return CFRetain(udat_isLenient(formatter
->_df
) ? kCFBooleanTrue
: kCFBooleanFalse
);
1185 } else if (kCFDateFormatterDoesRelativeDateFormattingKey
== key
) {
1186 if (formatter
->_property
._DoesRelativeDateFormatting
) return CFRetain(formatter
->_property
._DoesRelativeDateFormatting
);
1187 return CFRetain(kCFBooleanFalse
);
1188 } else if (kCFDateFormatterCalendarKey
== key
) {
1189 if (formatter
->_property
._Calendar
) return CFRetain(formatter
->_property
._Calendar
);
1190 CFCalendarRef calendar
= (CFCalendarRef
)CFLocaleGetValue(formatter
->_locale
, kCFLocaleCalendarKey
);
1191 return calendar
? CFRetain(calendar
) : NULL
;
1192 } else if (kCFDateFormatterCalendarIdentifierKey
== key
) {
1193 if (formatter
->_property
._CalendarName
) return CFRetain(formatter
->_property
._CalendarName
);
1194 CFStringRef ident
= (CFStringRef
)CFLocaleGetValue(formatter
->_locale
, kCFLocaleCalendarIdentifierKey
);
1195 return ident
? CFRetain(ident
) : NULL
;
1196 } else if (kCFDateFormatterTimeZoneKey
== key
) {
1197 if (formatter
->_property
._TwoDigitStartDate
) return CFRetain(formatter
->_property
._TwoDigitStartDate
);
1198 return CFRetain(formatter
->_property
._TimeZone
);
1199 } else if (kCFDateFormatterDefaultFormatKey
== key
) {
1200 return formatter
->_defformat
? CFRetain(formatter
->_defformat
) : NULL
;
1201 } else if (kCFDateFormatterTwoDigitStartDateKey
== key
) {
1202 if (formatter
->_property
._TwoDigitStartDate
) return CFRetain(formatter
->_property
._TwoDigitStartDate
);
1203 UDate udate
= udat_get2DigitYearStart(formatter
->_df
, &status
);
1204 if (U_SUCCESS(status
)) {
1205 CFAbsoluteTime at
= (double)udate
/ 1000.0 - kCFAbsoluteTimeIntervalSince1970
;
1206 return CFDateCreate(CFGetAllocator(formatter
), at
);
1208 } else if (kCFDateFormatterDefaultDateKey
== key
) {
1209 return formatter
->_property
._DefaultDate
? CFRetain(formatter
->_property
._DefaultDate
) : NULL
;
1210 } else if (kCFDateFormatterGregorianStartDateKey
== key
) {
1211 if (formatter
->_property
._GregorianStartDate
) return CFRetain(formatter
->_property
._GregorianStartDate
);
1212 UCalendar
*cal
= (UCalendar
*)udat_getCalendar(formatter
->_df
);
1213 UDate udate
= ucal_getGregorianChange(cal
, &status
);
1214 if (U_SUCCESS(status
)) {
1215 CFAbsoluteTime at
= (double)udate
/ 1000.0 - kCFAbsoluteTimeIntervalSince1970
;
1216 return CFDateCreate(CFGetAllocator(formatter
), at
);
1218 } else if (kCFDateFormatterEraSymbolsKey
== key
) {
1219 if (formatter
->_property
._EraSymbols
) return CFRetain(formatter
->_property
._EraSymbols
);
1220 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_ERAS
, 0);
1221 } else if (kCFDateFormatterLongEraSymbolsKey
== key
) {
1222 if (formatter
->_property
._LongEraSymbols
) return CFRetain(formatter
->_property
._LongEraSymbols
);
1223 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_ERA_NAMES
, 0);
1224 } else if (kCFDateFormatterMonthSymbolsKey
== key
) {
1225 if (formatter
->_property
._MonthSymbols
) return CFRetain(formatter
->_property
._MonthSymbols
);
1226 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_MONTHS
, 0);
1227 } else if (kCFDateFormatterShortMonthSymbolsKey
== key
) {
1228 if (formatter
->_property
._ShortMonthSymbols
) return CFRetain(formatter
->_property
._ShortMonthSymbols
);
1229 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_SHORT_MONTHS
, 0);
1230 } else if (kCFDateFormatterVeryShortMonthSymbolsKey
== key
) {
1231 if (formatter
->_property
._VeryShortMonthSymbols
) return CFRetain(formatter
->_property
._VeryShortMonthSymbols
);
1232 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_NARROW_MONTHS
, 0);
1233 } else if (kCFDateFormatterStandaloneMonthSymbolsKey
== key
) {
1234 if (formatter
->_property
._StandaloneMonthSymbols
) return CFRetain(formatter
->_property
._StandaloneMonthSymbols
);
1235 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_MONTHS
, 0);
1236 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey
== key
) {
1237 if (formatter
->_property
._ShortStandaloneMonthSymbols
) return CFRetain(formatter
->_property
._ShortStandaloneMonthSymbols
);
1238 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_SHORT_MONTHS
, 0);
1239 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey
== key
) {
1240 if (formatter
->_property
._VeryShortStandaloneMonthSymbols
) return CFRetain(formatter
->_property
._VeryShortStandaloneMonthSymbols
);
1241 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_NARROW_MONTHS
, 0);
1242 } else if (kCFDateFormatterWeekdaySymbolsKey
== key
) {
1243 if (formatter
->_property
._WeekdaySymbols
) return CFRetain(formatter
->_property
._WeekdaySymbols
);
1244 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_WEEKDAYS
, 1);
1245 } else if (kCFDateFormatterShortWeekdaySymbolsKey
== key
) {
1246 if (formatter
->_property
._ShortWeekdaySymbols
) return CFRetain(formatter
->_property
._ShortWeekdaySymbols
);
1247 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_SHORT_WEEKDAYS
, 1);
1248 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey
== key
) {
1249 if (formatter
->_property
._VeryShortWeekdaySymbols
) return CFRetain(formatter
->_property
._VeryShortWeekdaySymbols
);
1250 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_NARROW_WEEKDAYS
, 1);
1251 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey
== key
) {
1252 if (formatter
->_property
._StandaloneWeekdaySymbols
) return CFRetain(formatter
->_property
._StandaloneWeekdaySymbols
);
1253 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_WEEKDAYS
, 1);
1254 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey
== key
) {
1255 if (formatter
->_property
._ShortStandaloneWeekdaySymbols
) return CFRetain(formatter
->_property
._ShortStandaloneWeekdaySymbols
);
1256 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_SHORT_WEEKDAYS
, 1);
1257 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey
== key
) {
1258 if (formatter
->_property
._VeryShortStandaloneWeekdaySymbols
) return CFRetain(formatter
->_property
._VeryShortStandaloneWeekdaySymbols
);
1259 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_NARROW_WEEKDAYS
, 1);
1260 } else if (kCFDateFormatterQuarterSymbolsKey
== key
) {
1261 if (formatter
->_property
._QuarterSymbols
) return CFRetain(formatter
->_property
._QuarterSymbols
);
1262 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_QUARTERS
, 0);
1263 } else if (kCFDateFormatterShortQuarterSymbolsKey
== key
) {
1264 if (formatter
->_property
._ShortQuarterSymbols
) return CFRetain(formatter
->_property
._ShortQuarterSymbols
);
1265 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_SHORT_QUARTERS
, 0);
1266 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey
== key
) {
1267 if (formatter
->_property
._StandaloneQuarterSymbols
) return CFRetain(formatter
->_property
._StandaloneQuarterSymbols
);
1268 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_QUARTERS
, 0);
1269 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey
== key
) {
1270 if (formatter
->_property
._ShortStandaloneQuarterSymbols
) return CFRetain(formatter
->_property
._ShortStandaloneQuarterSymbols
);
1271 return __CFDateFormatterGetSymbolsArray(formatter
->_df
, UDAT_STANDALONE_SHORT_QUARTERS
, 0);
1272 } else if (kCFDateFormatterAMSymbolKey
== key
) {
1273 if (formatter
->_property
._AMSymbol
) return CFRetain(formatter
->_property
._AMSymbol
);
1274 CFIndex cnt
= udat_countSymbols(formatter
->_df
, UDAT_AM_PMS
);
1276 CFIndex ucnt
= udat_getSymbols(formatter
->_df
, UDAT_AM_PMS
, 0, ubuffer
, BUFFER_SIZE
, &status
);
1277 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1278 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (UniChar
*)ubuffer
, ucnt
);
1281 } else if (kCFDateFormatterPMSymbolKey
== key
) {
1282 if (formatter
->_property
._PMSymbol
) return CFRetain(formatter
->_property
._PMSymbol
);
1283 CFIndex cnt
= udat_countSymbols(formatter
->_df
, UDAT_AM_PMS
);
1285 CFIndex ucnt
= udat_getSymbols(formatter
->_df
, UDAT_AM_PMS
, 1, ubuffer
, BUFFER_SIZE
, &status
);
1286 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1287 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (UniChar
*)ubuffer
, ucnt
);
1291 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);