2 * Copyright (c) 2015 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) 1998-2014, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
30 #include <CoreFoundation/CFTimeZone.h>
31 #include <CoreFoundation/CFPropertyList.h>
32 #include <CoreFoundation/CFDateFormatter.h>
33 #include <CoreFoundation/CFPriv.h>
34 #include "CFInternal.h"
41 #include <unicode/ucal.h>
42 #include <CoreFoundation/CFDateFormatter.h>
43 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX
46 #include <sys/fcntl.h>
48 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
50 #elif DEPLOYMENT_TARGET_LINUX
52 #define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
53 #endif /* !defined TZDIR */
56 #define TZDEFAULT "/etc/localtime"
57 #endif /* !defined TZDEFAULT */
60 char tzh_magic
[4]; /* TZ_MAGIC */
61 char tzh_reserved
[16]; /* reserved for future use */
62 char tzh_ttisgmtcnt
[4]; /* coded number of trans. time flags */
63 char tzh_ttisstdcnt
[4]; /* coded number of trans. time flags */
64 char tzh_leapcnt
[4]; /* coded number of leap seconds */
65 char tzh_timecnt
[4]; /* coded number of transition times */
66 char tzh_typecnt
[4]; /* coded number of local time types */
67 char tzh_charcnt
[4]; /* coded number of abbr. chars */
71 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX
72 #define TZZONELINK TZDEFAULT
73 #define TZZONEINFO TZDIR "/"
74 #elif DEPLOYMENT_TARGET_WINDOWS
75 static CFStringRef __tzZoneInfo
= NULL
;
76 static char *__tzDir
= NULL
;
77 static void __InitTZStrings(void);
79 #error Unknown or unspecified DEPLOYMENT_TARGET
82 #if DEPLOYMENT_TARGET_LINUX
84 CF_EXPORT CFStringRef
const kCFDateFormatterTimeZone
__attribute__((weak
, alias ("kCFDateFormatterTimeZoneKey")));
87 CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification
, "kCFTimeZoneSystemTimeZoneDidChangeNotification")
89 static CFTimeZoneRef __CFTimeZoneSystem
= NULL
;
90 static CFTimeZoneRef __CFTimeZoneDefault
= NULL
;
91 static CFDictionaryRef __CFTimeZoneAbbreviationDict
= NULL
;
92 static CFLock_t __CFTimeZoneAbbreviationLock
= CFLockInit
;
93 static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict
= NULL
;
94 static CFLock_t __CFTimeZoneCompatibilityMappingLock
= CFLockInit
;
95 static CFArrayRef __CFKnownTimeZoneList
= NULL
;
96 static CFMutableDictionaryRef __CFTimeZoneCache
= NULL
;
97 static CFLock_t __CFTimeZoneGlobalLock
= CFLockInit
;
99 #if DEPLOYMENT_TARGET_WINDOWS
100 static CFDictionaryRef __CFTimeZoneWinToOlsonDict
= NULL
;
101 static CFLock_t __CFTimeZoneWinToOlsonLock
= CFLockInit
;
104 CF_INLINE
void __CFTimeZoneLockGlobal(void) {
105 __CFLock(&__CFTimeZoneGlobalLock
);
108 CF_INLINE
void __CFTimeZoneUnlockGlobal(void) {
109 __CFUnlock(&__CFTimeZoneGlobalLock
);
112 CF_INLINE
void __CFTimeZoneLockAbbreviations(void) {
113 __CFLock(&__CFTimeZoneAbbreviationLock
);
116 CF_INLINE
void __CFTimeZoneUnlockAbbreviations(void) {
117 __CFUnlock(&__CFTimeZoneAbbreviationLock
);
120 CF_INLINE
void __CFTimeZoneLockCompatibilityMapping(void) {
121 __CFLock(&__CFTimeZoneCompatibilityMappingLock
);
124 CF_INLINE
void __CFTimeZoneUnlockCompatibilityMapping(void) {
125 __CFUnlock(&__CFTimeZoneCompatibilityMappingLock
);
128 #if DEPLOYMENT_TARGET_WINDOWS
129 /* This function should be used for WIN32 instead of
130 * __CFCopyRecursiveDirectoryList function.
131 * It takes TimeZone names from the registry
132 * (Aleksey Dukhnyakov)
134 static CFMutableArrayRef
__CFCopyWindowsTimeZoneList() {
135 CFMutableArrayRef result
= NULL
;
137 TCHAR lpName
[MAX_PATH
+1];
138 DWORD dwIndex
, retCode
;
140 if (RegOpenKey(HKEY_LOCAL_MACHINE
,_T(TZZONEINFO
),&hkResult
) !=
144 result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
145 for (dwIndex
=0; (retCode
= RegEnumKey(hkResult
,dwIndex
,lpName
,MAX_PATH
)) != ERROR_NO_MORE_ITEMS
; dwIndex
++) {
146 if (retCode
!= ERROR_SUCCESS
) {
147 RegCloseKey(hkResult
);
152 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (const UInt8
*)lpName
, (_tcslen(lpName
) * sizeof(UniChar
)), kCFStringEncodingUnicode
, false);
154 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, lpName
, _tcslen(lpName
), CFStringGetSystemEncoding(), false);
156 CFArrayAppendValue(result
, string
);
161 RegCloseKey(hkResult
);
164 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
165 static CFMutableArrayRef
__CFCopyRecursiveDirectoryList() {
166 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
167 #if DEPLOYMENT_TARGET_WINDOWS
168 if (!__tzDir
) __InitTZStrings();
169 if (!__tzDir
) return result
;
170 int fd
= open(__tzDir
, O_RDONLY
);
172 int fd
= open(TZDIR
"/zone.tab", O_RDONLY
);
176 uint8_t buffer
[4096];
177 ssize_t len
= read(fd
, buffer
, sizeof(buffer
));
179 if (len
< sizeof(buffer
)) {
180 // assumes that partial read only occurs at the end of the file
184 const uint8_t *bytes
= buffer
;
186 const uint8_t *nextl
= memchr(bytes
, '\n', len
);
190 len
-= (nextl
- bytes
);
194 const uint8_t *tab1
= memchr(bytes
, '\t', (nextl
- bytes
));
196 len
-= (nextl
- bytes
);
201 len
-= (tab1
- bytes
);
203 const uint8_t *tab2
= memchr(bytes
, '\t', (nextl
- bytes
));
205 len
-= (nextl
- bytes
);
210 len
-= (tab2
- bytes
);
212 const uint8_t *tab3
= memchr(bytes
, '\t', (nextl
- bytes
));
213 int nmlen
= tab3
? (tab3
- bytes
) : (nextl
- 1 - bytes
);
214 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, bytes
, nmlen
, kCFStringEncodingUTF8
, false);
215 CFArrayAppendValue(result
, string
);
217 len
-= (nextl
- bytes
);
220 lseek(fd
, -len
, SEEK_CUR
);
226 #error Unknown or unspecified DEPLOYMENT_TARGET
229 typedef struct _CFTZPeriod
{
235 struct __CFTimeZone
{
237 CFStringRef _name
; /* immutable */
238 CFDataRef _data
; /* immutable */
239 CFTZPeriod
*_periods
; /* immutable */
240 int32_t _periodCnt
; /* immutable */
243 /* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates
244 * between 1933 and 2069; info outside these years is discarded on read-in */
245 /* Bits 31-18 of the info are unused */
246 /* Bit 17 of the info is used for the is-DST state */
247 /* Bit 16 of the info is used for the sign of the offset (1 == negative) */
248 /* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */
250 CF_INLINE
void __CFTZPeriodInit(CFTZPeriod
*period
, int32_t startTime
, CFStringRef abbrev
, int32_t offset
, Boolean isDST
) {
251 period
->startSec
= startTime
;
252 period
->abbrev
= abbrev
? (CFStringRef
)CFRetain(abbrev
) : NULL
;
253 __CFBitfieldSetValue(period
->info
, 15, 0, abs(offset
));
254 __CFBitfieldSetValue(period
->info
, 16, 16, (offset
< 0 ? 1 : 0));
255 __CFBitfieldSetValue(period
->info
, 17, 17, (isDST
? 1 : 0));
258 CF_INLINE
int32_t __CFTZPeriodStartSeconds(const CFTZPeriod
*period
) {
259 return period
->startSec
;
262 CF_INLINE CFStringRef
__CFTZPeriodAbbreviation(const CFTZPeriod
*period
) {
263 return period
->abbrev
;
266 CF_INLINE
int32_t __CFTZPeriodGMTOffset(const CFTZPeriod
*period
) {
267 int32_t v
= __CFBitfieldGetValue(period
->info
, 15, 0);
268 if (__CFBitfieldGetValue(period
->info
, 16, 16)) v
= -v
;
272 CF_INLINE Boolean
__CFTZPeriodIsDST(const CFTZPeriod
*period
) {
273 return (Boolean
)__CFBitfieldGetValue(period
->info
, 17, 17);
276 static CFComparisonResult
__CFCompareTZPeriods(const void *val1
, const void *val2
, void *context
) {
277 CFTZPeriod
*tzp1
= (CFTZPeriod
*)val1
;
278 CFTZPeriod
*tzp2
= (CFTZPeriod
*)val2
;
279 // we treat equal as less than, as the code which uses the
280 // result of the bsearch doesn't expect exact matches
281 // (they're pretty rare, so no point in over-coding for them)
282 if (__CFTZPeriodStartSeconds(tzp1
) <= __CFTZPeriodStartSeconds(tzp2
)) return kCFCompareLessThan
;
283 return kCFCompareGreaterThan
;
286 static CFIndex
__CFBSearchTZPeriods(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
288 __CFTZPeriodInit(&elem
, (int32_t)floor(at
+ 1.0), NULL
, 0, false);
289 CFIndex idx
= CFBSearch(&elem
, sizeof(CFTZPeriod
), tz
->_periods
, tz
->_periodCnt
, __CFCompareTZPeriods
, NULL
);
290 if (tz
->_periodCnt
<= idx
) {
291 idx
= tz
->_periodCnt
;
292 } else if (0 == idx
) {
299 CF_INLINE
int32_t __CFDetzcode(const unsigned char *bufp
) {
300 int32_t result
= (bufp
[0] & 0x80) ? ~0L : 0L;
301 result
= (result
<< 8) | (bufp
[0] & 0xff);
302 result
= (result
<< 8) | (bufp
[1] & 0xff);
303 result
= (result
<< 8) | (bufp
[2] & 0xff);
304 result
= (result
<< 8) | (bufp
[3] & 0xff);
308 CF_INLINE
void __CFEntzcode(int32_t value
, unsigned char *bufp
) {
309 bufp
[0] = (value
>> 24) & 0xff;
310 bufp
[1] = (value
>> 16) & 0xff;
311 bufp
[2] = (value
>> 8) & 0xff;
312 bufp
[3] = (value
>> 0) & 0xff;
315 static Boolean
__CFParseTimeZoneData(CFAllocatorRef allocator
, CFDataRef data
, CFTZPeriod
**tzpp
, CFIndex
*cntp
) {
316 int32_t len
, timecnt
, typecnt
, charcnt
, idx
, cnt
;
317 const uint8_t *p
, *timep
, *typep
, *ttisp
, *charp
;
319 Boolean result
= true;
321 p
= CFDataGetBytePtr(data
);
322 len
= CFDataGetLength(data
);
323 if (len
< (int32_t)sizeof(struct tzhead
)) {
327 if (!(p
[0] == 'T' && p
[1] == 'Z' && p
[2] == 'i' && p
[3] == 'f')) return false; /* Don't parse without TZif at head of file */
329 p
+= 20 + 4 + 4 + 4; /* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */
330 timecnt
= __CFDetzcode(p
);
332 typecnt
= __CFDetzcode(p
);
334 charcnt
= __CFDetzcode(p
);
336 if (typecnt
<= 0 || timecnt
< 0 || charcnt
< 0) {
339 if (1024 < timecnt
|| 32 < typecnt
|| 128 < charcnt
) {
340 // reject excessive timezones to avoid arithmetic overflows for
341 // security reasons and to reject potentially corrupt files
344 if (len
- (int32_t)sizeof(struct tzhead
) < (4 + 1) * timecnt
+ (4 + 1 + 1) * typecnt
+ charcnt
) {
348 typep
= timep
+ 4 * timecnt
;
349 ttisp
= typep
+ timecnt
;
350 charp
= ttisp
+ (4 + 1 + 1) * typecnt
;
351 cnt
= (0 < timecnt
) ? timecnt
: 1;
352 *tzpp
= CFAllocatorAllocate(allocator
, cnt
* sizeof(CFTZPeriod
), 0);
353 if (__CFOASafe
) __CFSetLastAllocationEventName(*tzpp
, "CFTimeZone (store)");
354 memset(*tzpp
, 0, cnt
* sizeof(CFTZPeriod
));
355 abbrs
= CFAllocatorAllocate(allocator
, (charcnt
+ 1) * sizeof(CFStringRef
), 0);
356 if (__CFOASafe
) __CFSetLastAllocationEventName(abbrs
, "CFTimeZone (temp)");
357 for (idx
= 0; idx
< charcnt
+ 1; idx
++) {
360 for (idx
= 0; idx
< cnt
; idx
++) {
362 int32_t itime
, offset
;
363 uint8_t type
, dst
, abbridx
;
365 at
= (CFAbsoluteTime
)(__CFDetzcode(timep
) + 0.0) - kCFAbsoluteTimeIntervalSince1970
;
366 if (0 == timecnt
) itime
= INT_MIN
;
367 else if (at
< (CFAbsoluteTime
)INT_MIN
) itime
= INT_MIN
;
368 else if ((CFAbsoluteTime
)INT_MAX
< at
) itime
= INT_MAX
;
369 else itime
= (int32_t)at
;
370 timep
+= 4; /* harmless if 0 == timecnt */
371 type
= (0 < timecnt
) ? (uint8_t)*typep
++ : 0;
372 if (typecnt
<= type
) {
376 offset
= __CFDetzcode(ttisp
+ 6 * type
);
377 dst
= (uint8_t)*(ttisp
+ 6 * type
+ 4);
378 if (0 != dst
&& 1 != dst
) {
382 abbridx
= (uint8_t)*(ttisp
+ 6 * type
+ 5);
383 if (charcnt
< abbridx
) {
387 if (NULL
== abbrs
[abbridx
]) {
388 abbrs
[abbridx
] = CFStringCreateWithCString(allocator
, (char *)&charp
[abbridx
], kCFStringEncodingASCII
);
390 __CFTZPeriodInit(*tzpp
+ idx
, itime
, abbrs
[abbridx
], offset
, (dst
? true : false));
392 for (idx
= 0; idx
< charcnt
+ 1; idx
++) {
393 if (NULL
!= abbrs
[idx
]) {
394 CFRelease(abbrs
[idx
]);
397 CFAllocatorDeallocate(allocator
, abbrs
);
399 // dump all but the last INT_MIN and the first INT_MAX
400 for (idx
= 0; idx
< cnt
; idx
++) {
401 if (((*tzpp
+ idx
)->startSec
== INT_MIN
) && (idx
+ 1 < cnt
) && (((*tzpp
+ idx
+ 1)->startSec
== INT_MIN
))) {
402 if (NULL
!= (*tzpp
+ idx
)->abbrev
) CFRelease((*tzpp
+ idx
)->abbrev
);
404 memmove((*tzpp
+ idx
), (*tzpp
+ idx
+ 1), sizeof(CFTZPeriod
) * (cnt
- idx
));
408 // Don't combine these loops! Watch the idx decrementing...
409 for (idx
= 0; idx
< cnt
; idx
++) {
410 if (((*tzpp
+ idx
)->startSec
== INT_MAX
) && (0 < idx
) && (((*tzpp
+ idx
- 1)->startSec
== INT_MAX
))) {
411 if (NULL
!= (*tzpp
+ idx
)->abbrev
) CFRelease((*tzpp
+ idx
)->abbrev
);
413 memmove((*tzpp
+ idx
), (*tzpp
+ idx
+ 1), sizeof(CFTZPeriod
) * (cnt
- idx
));
417 CFQSortArray(*tzpp
, cnt
, sizeof(CFTZPeriod
), __CFCompareTZPeriods
, NULL
);
418 // if the first period is in DST and there is more than one period, drop it
419 if (1 < cnt
&& __CFTZPeriodIsDST(*tzpp
+ 0)) {
420 if (NULL
!= (*tzpp
+ 0)->abbrev
) CFRelease((*tzpp
+ 0)->abbrev
);
422 memmove((*tzpp
+ 0), (*tzpp
+ 0 + 1), sizeof(CFTZPeriod
) * (cnt
- 0));
426 CFAllocatorDeallocate(allocator
, *tzpp
);
432 static Boolean
__CFTimeZoneEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
433 CFTimeZoneRef tz1
= (CFTimeZoneRef
)cf1
;
434 CFTimeZoneRef tz2
= (CFTimeZoneRef
)cf2
;
435 if (!CFEqual(CFTimeZoneGetName(tz1
), CFTimeZoneGetName(tz2
))) return false;
436 if (!CFEqual(CFTimeZoneGetData(tz1
), CFTimeZoneGetData(tz2
))) return false;
440 static CFHashCode
__CFTimeZoneHash(CFTypeRef cf
) {
441 CFTimeZoneRef tz
= (CFTimeZoneRef
)cf
;
442 return CFHash(CFTimeZoneGetName(tz
));
445 static CFStringRef
__CFTimeZoneCopyDescription(CFTypeRef cf
) {
446 CFTimeZoneRef tz
= (CFTimeZoneRef
)cf
;
447 CFStringRef result
, abbrev
;
449 at
= CFAbsoluteTimeGetCurrent();
450 abbrev
= CFTimeZoneCopyAbbreviation(tz
, at
);
451 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFTimeZone %p [%p]>{name = %@; abbreviation = %@; GMT offset = %g; is DST = %s}"), cf
, CFGetAllocator(tz
), tz
->_name
, abbrev
, CFTimeZoneGetSecondsFromGMT(tz
, at
), CFTimeZoneIsDaylightSavingTime(tz
, at
) ? "true" : "false");
456 static void __CFTimeZoneDeallocate(CFTypeRef cf
) {
457 CFTimeZoneRef tz
= (CFTimeZoneRef
)cf
;
458 CFAllocatorRef allocator
= CFGetAllocator(tz
);
460 if (tz
->_name
) CFRelease(tz
->_name
);
461 if (tz
->_data
) CFRelease(tz
->_data
);
462 for (idx
= 0; idx
< tz
->_periodCnt
; idx
++) {
463 if (NULL
!= tz
->_periods
[idx
].abbrev
) CFRelease(tz
->_periods
[idx
].abbrev
);
465 if (NULL
!= tz
->_periods
) CFAllocatorDeallocate(allocator
, tz
->_periods
);
468 static CFTypeID __kCFTimeZoneTypeID
= _kCFRuntimeNotATypeID
;
470 static const CFRuntimeClass __CFTimeZoneClass
= {
475 __CFTimeZoneDeallocate
,
479 __CFTimeZoneCopyDescription
482 CFTypeID
CFTimeZoneGetTypeID(void) {
483 static dispatch_once_t initOnce
;
484 dispatch_once(&initOnce
, ^{ __kCFTimeZoneTypeID
= _CFRuntimeRegisterClass(&__CFTimeZoneClass
); });
485 return __kCFTimeZoneTypeID
;
488 #if DEPLOYMENT_TARGET_WINDOWS
489 static const char *__CFTimeZoneWinToOlsonDefaults
=
490 /* Mappings to time zones in Windows Registry are best-guess */
491 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
492 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
493 " <plist version=\"1.0\">"
495 " <key>Afghanistan</key> <string>Asia/Kabul</string>"
496 " <key>Afghanistan Standard Time</key> <string>Asia/Kabul</string>"
497 " <key>Alaskan</key> <string>America/Anchorage</string>"
498 " <key>Alaskan Standard Time</key> <string>America/Anchorage</string>"
499 " <key>Arab</key> <string>Asia/Riyadh</string>"
500 " <key>Arab Standard Time</key> <string>Asia/Riyadh</string>"
501 " <key>Arabian</key> <string>Asia/Muscat</string>"
502 " <key>Arabian Standard Time</key> <string>Asia/Muscat</string>"
503 " <key>Arabic Standard Time</key> <string>Asia/Baghdad</string>"
504 " <key>Atlantic</key> <string>America/Halifax</string>"
505 " <key>Atlantic Standard Time</key> <string>America/Halifax</string>"
506 " <key>AUS Central</key> <string>Australia/Darwin</string>"
507 " <key>AUS Central Standard Time</key> <string>Australia/Darwin</string>"
508 " <key>AUS Eastern</key> <string>Australia/Sydney</string>"
509 " <key>AUS Eastern Standard Time</key> <string>Australia/Sydney</string>"
510 " <key>Azerbaijan Standard Time</key> <string>Asia/Baku</string>"
511 " <key>Azores</key> <string>Atlantic/Azores</string>"
512 " <key>Azores Standard Time</key> <string>Atlantic/Azores</string>"
513 " <key>Bangkok</key> <string>Asia/Bangkok</string>"
514 " <key>Bangkok Standard Time</key> <string>Asia/Bangkok</string>"
515 " <key>Beijing</key> <string>Asia/Shanghai</string>"
516 " <key>Canada Central</key> <string>America/Regina</string>"
517 " <key>Canada Central Standard Time</key> <string>America/Regina</string>"
518 " <key>Cape Verde Standard Time</key> <string>Atlantic/Cape_Verde</string>"
519 " <key>Caucasus</key> <string>Asia/Yerevan</string>"
520 " <key>Caucasus Standard Time</key> <string>Asia/Yerevan</string>"
521 " <key>Cen. Australia</key> <string>Australia/Adelaide</string>"
522 " <key>Cen. Australia Standard Time</key> <string>Australia/Adelaide</string>"
523 " <key>Central</key> <string>America/Chicago</string>"
524 " <key>Central America Standard Time</key> <string>America/Regina</string>"
525 " <key>Central Asia</key> <string>Asia/Dhaka</string>"
526 " <key>Central Asia Standard Time</key> <string>Asia/Dhaka</string>"
527 " <key>Central Brazilian Standard Time</key> <string>America/Manaus</string>"
528 " <key>Central Europe</key> <string>Europe/Prague</string>"
529 " <key>Central Europe Standard Time</key> <string>Europe/Prague</string>"
530 " <key>Central European</key> <string>Europe/Belgrade</string>"
531 " <key>Central European Standard Time</key> <string>Europe/Belgrade</string>"
532 " <key>Central Pacific</key> <string>Pacific/Guadalcanal</string>"
533 " <key>Central Pacific Standard Time</key> <string>Pacific/Guadalcanal</string>"
534 " <key>Central Standard Time</key> <string>America/Chicago</string>"
535 " <key>Central Standard Time (Mexico)</key> <string>America/Mexico_City</string>"
536 " <key>China</key> <string>Asia/Shanghai</string>"
537 " <key>China Standard Time</key> <string>Asia/Shanghai</string>"
538 " <key>Dateline</key> <string>GMT-1200</string>"
539 " <key>Dateline Standard Time</key> <string>GMT-1200</string>"
540 " <key>E. Africa</key> <string>Africa/Nairobi</string>"
541 " <key>E. Africa Standard Time</key> <string>Africa/Nairobi</string>"
542 " <key>E. Australia</key> <string>Australia/Brisbane</string>"
543 " <key>E. Australia Standard Time</key> <string>Australia/Brisbane</string>"
544 " <key>E. Europe</key> <string>Europe/Minsk</string>"
545 " <key>E. Europe Standard Time</key> <string>Europe/Minsk</string>"
546 " <key>E. South America</key> <string>America/Sao_Paulo</string>"
547 " <key>E. South America Standard Time</key> <string>America/Sao_Paulo</string>"
548 " <key>Eastern</key> <string>America/New_York</string>"
549 " <key>Eastern Standard Time</key> <string>America/New_York</string>"
550 " <key>Egypt</key> <string>Africa/Cairo</string>"
551 " <key>Egypt Standard Time</key> <string>Africa/Cairo</string>"
552 " <key>Ekaterinburg</key> <string>Asia/Yekaterinburg</string>"
553 " <key>Ekaterinburg Standard Time</key> <string>Asia/Yekaterinburg</string>"
554 " <key>Fiji</key> <string>Pacific/Fiji</string>"
555 " <key>Fiji Standard Time</key> <string>Pacific/Fiji</string>"
556 " <key>FLE</key> <string>Europe/Helsinki</string>"
557 " <key>FLE Standard Time</key> <string>Europe/Helsinki</string>"
558 " <key>Georgian Standard Time</key> <string>Asia/Tbilisi</string>"
559 " <key>GFT</key> <string>Europe/Athens</string>"
560 " <key>GFT Standard Time</key> <string>Europe/Athens</string>"
561 " <key>GMT</key> <string>Europe/London</string>"
562 " <key>GMT Standard Time</key> <string>Europe/London</string>"
563 " <key>Greenland Standard Time</key> <string>America/Godthab</string>"
564 " <key>Greenwich</key> <string>GMT</string>"
565 " <key>Greenwich Standard Time</key> <string>GMT</string>"
566 " <key>GTB</key> <string>Europe/Athens</string>"
567 " <key>GTB Standard Time</key> <string>Europe/Athens</string>"
568 " <key>Hawaiian</key> <string>Pacific/Honolulu</string>"
569 " <key>Hawaiian Standard Time</key> <string>Pacific/Honolulu</string>"
570 " <key>India</key> <string>Asia/Calcutta</string>"
571 " <key>India Standard Time</key> <string>Asia/Calcutta</string>"
572 " <key>Iran</key> <string>Asia/Tehran</string>"
573 " <key>Iran Standard Time</key> <string>Asia/Tehran</string>"
574 " <key>Israel</key> <string>Asia/Jerusalem</string>"
575 " <key>Israel Standard Time</key> <string>Asia/Jerusalem</string>"
576 " <key>Jordan Standard Time</key> <string>Asia/Amman</string>"
577 " <key>Korea</key> <string>Asia/Seoul</string>"
578 " <key>Korea Standard Time</key> <string>Asia/Seoul</string>"
579 " <key>Mexico</key> <string>America/Mexico_City</string>"
580 " <key>Mexico Standard Time</key> <string>America/Mexico_City</string>"
581 " <key>Mexico Standard Time 2</key> <string>America/Chihuahua</string>"
582 " <key>Mid-Atlantic</key> <string>Atlantic/South_Georgia</string>"
583 " <key>Mid-Atlantic Standard Time</key> <string>Atlantic/South_Georgia</string>"
584 " <key>Middle East Standard Time</key> <string>Asia/Beirut</string>"
585 " <key>Mountain</key> <string>America/Denver</string>"
586 " <key>Mountain Standard Time</key> <string>America/Denver</string>"
587 " <key>Mountain Standard Time (Mexico)</key> <string>America/Chihuahua</string>"
588 " <key>Myanmar Standard Time</key> <string>Asia/Rangoon</string>"
589 " <key>N. Central Asia Standard Time</key> <string>Asia/Novosibirsk</string>"
590 " <key>Namibia Standard Time</key> <string>Africa/Windhoek</string>"
591 " <key>Nepal Standard Time</key> <string>Asia/Katmandu</string>"
592 " <key>New Zealand</key> <string>Pacific/Auckland</string>"
593 " <key>New Zealand Standard Time</key> <string>Pacific/Auckland</string>"
594 " <key>Newfoundland</key> <string>America/St_Johns</string>"
595 " <key>Newfoundland Standard Time</key> <string>America/St_Johns</string>"
596 " <key>North Asia East Standard Time</key> <string>Asia/Ulaanbaatar</string>"
597 " <key>North Asia Standard Time</key> <string>Asia/Krasnoyarsk</string>"
598 " <key>Pacific</key> <string>America/Los_Angeles</string>"
599 " <key>Pacific SA</key> <string>America/Santiago</string>"
600 " <key>Pacific SA Standard Time</key> <string>America/Santiago</string>"
601 " <key>Pacific Standard Time</key> <string>America/Los_Angeles</string>"
602 " <key>Pacific Standard Time (Mexico)</key> <string>America/Tijuana</string>"
603 " <key>Prague Bratislava</key> <string>Europe/Prague</string>"
604 " <key>Romance</key> <string>Europe/Paris</string>"
605 " <key>Romance Standard Time</key> <string>Europe/Paris</string>"
606 " <key>Russian</key> <string>Europe/Moscow</string>"
607 " <key>Russian Standard Time</key> <string>Europe/Moscow</string>"
608 " <key>SA Eastern</key> <string>America/Buenos_Aires</string>"
609 " <key>SA Eastern Standard Time</key> <string>America/Buenos_Aires</string>"
610 " <key>SA Pacific</key> <string>America/Bogota</string>"
611 " <key>SA Pacific Standard Time</key> <string>America/Bogota</string>"
612 " <key>SA Western</key> <string>America/Caracas</string>"
613 " <key>SA Western Standard Time</key> <string>America/Caracas</string>"
614 " <key>Samoa</key> <string>Pacific/Apia</string>"
615 " <key>Samoa Standard Time</key> <string>Pacific/Apia</string>"
616 " <key>Saudi Arabia</key> <string>Asia/Riyadh</string>"
617 " <key>Saudi Arabia Standard Time</key> <string>Asia/Riyadh</string>"
618 " <key>SE Asia Standard Time</key> <string>Asia/Bangkok</string>"
619 " <key>Singapore</key> <string>Asia/Singapore</string>"
620 " <key>Singapore Standard Time</key> <string>Asia/Singapore</string>"
621 " <key>South Africa</key> <string>Africa/Harare</string>"
622 " <key>South Africa Standard Time</key> <string>Africa/Harare</string>"
623 " <key>Sri Lanka</key> <string>Asia/Colombo</string>"
624 " <key>Sri Lanka Standard Time</key> <string>Asia/Colombo</string>"
625 " <key>Sydney Standard Time</key> <string>Australia/Sydney</string>"
626 " <key>Taipei</key> <string>Asia/Taipei</string>"
627 " <key>Taipei Standard Time</key> <string>Asia/Taipei</string>"
628 " <key>Tasmania</key> <string>Australia/Hobart</string>"
629 " <key>Tasmania Standard Time</key> <string>Australia/Hobart</string>"
630 " <key>Tasmania Standard Time</key> <string>Australia/Hobart</string>"
631 " <key>Tokyo</key> <string>Asia/Tokyo</string>"
632 " <key>Tokyo Standard Time</key> <string>Asia/Tokyo</string>"
633 " <key>Tonga Standard Time</key> <string>Pacific/Tongatapu</string>"
634 " <key>US Eastern</key> <string>America/Indianapolis</string>"
635 " <key>US Eastern Standard Time</key> <string>America/Indianapolis</string>"
636 " <key>US Mountain</key> <string>America/Phoenix</string>"
637 " <key>US Mountain Standard Time</key> <string>America/Phoenix</string>"
638 " <key>Vladivostok</key> <string>Asia/Vladivostok</string>"
639 " <key>Vladivostok Standard Time</key> <string>Asia/Vladivostok</string>"
640 " <key>W. Australia</key> <string>Australia/Perth</string>"
641 " <key>W. Australia Standard Time</key> <string>Australia/Perth</string>"
642 " <key>W. Central Africa Standard Time</key> <string>Africa/Luanda</string>"
643 " <key>W. Europe</key> <string>Europe/Berlin</string>"
644 " <key>W. Europe Standard Time</key> <string>Europe/Berlin</string>"
645 " <key>Warsaw</key> <string>Europe/Warsaw</string>"
646 " <key>West Asia</key> <string>Asia/Karachi</string>"
647 " <key>West Asia Standard Time</key> <string>Asia/Karachi</string>"
648 " <key>West Pacific</key> <string>Pacific/Guam</string>"
649 " <key>West Pacific Standard Time</key> <string>Pacific/Guam</string>"
650 " <key>Western Brazilian Standard Time</key> <string>America/Rio_Branco</string>"
651 " <key>Yakutsk</key> <string>Asia/Yakutsk</string>"
655 CF_INLINE
void __CFTimeZoneLockWinToOlson(void) {
656 __CFLock(&__CFTimeZoneWinToOlsonLock
);
659 CF_INLINE
void __CFTimeZoneUnlockWinToOlson(void) {
660 __CFUnlock(&__CFTimeZoneWinToOlsonLock
);
663 CFDictionaryRef
CFTimeZoneCopyWinToOlsonDictionary(void) {
664 CFDictionaryRef dict
;
665 __CFTimeZoneLockWinToOlson();
666 if (NULL
== __CFTimeZoneWinToOlsonDict
) {
667 CFDataRef data
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)__CFTimeZoneWinToOlsonDefaults
, strlen(__CFTimeZoneWinToOlsonDefaults
));
668 __CFTimeZoneWinToOlsonDict
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, data
, kCFPropertyListImmutable
, NULL
);
671 if (NULL
== __CFTimeZoneWinToOlsonDict
) {
672 __CFTimeZoneWinToOlsonDict
= CFDictionaryCreate(kCFAllocatorSystemDefault
, NULL
, NULL
, 0, NULL
, NULL
);
674 dict
= __CFTimeZoneWinToOlsonDict
? (CFDictionaryRef
)CFRetain(__CFTimeZoneWinToOlsonDict
) : NULL
;
675 __CFTimeZoneUnlockWinToOlson();
679 void CFTimeZoneSetWinToOlsonDictionary(CFDictionaryRef dict
) {
680 __CFGenericValidateType(dict
, CFDictionaryGetTypeID());
681 __CFTimeZoneLockWinToOlson();
682 if (dict
!= __CFTimeZoneWinToOlsonDict
) {
683 if (dict
) CFRetain(dict
);
684 if (__CFTimeZoneWinToOlsonDict
) CFRelease(__CFTimeZoneWinToOlsonDict
);
685 __CFTimeZoneWinToOlsonDict
= dict
;
687 __CFTimeZoneUnlockWinToOlson();
690 CFTimeZoneRef
CFTimeZoneCreateWithWindowsName(CFAllocatorRef allocator
, CFStringRef winName
) {
691 if (!winName
) return NULL
;
693 CFDictionaryRef winToOlson
= CFTimeZoneCopyWinToOlsonDictionary();
694 if (!winToOlson
) return NULL
;
696 CFStringRef olsonName
= CFDictionaryGetValue(winToOlson
, winName
);
697 CFTimeZoneRef retval
= NULL
;
699 retval
= CFTimeZoneCreateWithName(allocator
, olsonName
, false);
701 CFRelease(winToOlson
);
705 extern CFStringRef
_CFGetWindowsAppleSystemLibraryDirectory(void);
706 void __InitTZStrings(void) {
707 static CFLock_t __CFTZDirLock
= CFLockInit
;
708 __CFLock(&__CFTZDirLock
);
710 CFStringRef winDir
= _CFGetWindowsAppleSystemLibraryDirectory();
711 __tzZoneInfo
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\\etc\\zoneinfo"), winDir
);
713 if (!__tzDir
&& __tzZoneInfo
) {
714 int length
= CFStringGetLength(__tzZoneInfo
) + sizeof("\\zone.tab") + 1;
715 __tzDir
= malloc(length
); // If we don't use ascii, we'll need to malloc more space
716 if (!__tzDir
|| !CFStringGetCString(__tzZoneInfo
, __tzDir
, length
, kCFStringEncodingASCII
)) {
719 strcat(__tzDir
, "\\zone.tab");
722 __CFUnlock(&__CFTZDirLock
);
726 static CFTimeZoneRef
__CFTimeZoneCreateSystem(void) {
727 CFTimeZoneRef result
= NULL
;
729 #if DEPLOYMENT_TARGET_WINDOWS
730 CFStringRef name
= NULL
;
731 TIME_ZONE_INFORMATION tzi
= { 0 };
732 DWORD rval
= GetTimeZoneInformation(&tzi
);
733 if (rval
!= TIME_ZONE_ID_INVALID
) {
734 LPWSTR standardName
= (LPWSTR
)&tzi
.StandardName
;
735 CFStringRef cfStandardName
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (UInt8
*)standardName
, wcslen(standardName
)*sizeof(WCHAR
), kCFStringEncodingUTF16LE
, false);
736 if (cfStandardName
) {
737 CFDictionaryRef winToOlson
= CFTimeZoneCopyWinToOlsonDictionary();
739 name
= CFDictionaryGetValue(winToOlson
, cfStandardName
);
740 if (name
) CFRetain(name
);
741 CFRelease(winToOlson
);
743 CFRelease(cfStandardName
);
746 CFLog(kCFLogLevelError
, CFSTR("Couldn't get time zone information error %d"), GetLastError());
752 char linkbuf
[CFMaxPathSize
];
754 tzenv
= __CFgetenv("TZFILE");
756 CFStringRef name
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (uint8_t *)tzenv
, strlen(tzenv
), kCFStringEncodingUTF8
, false);
757 result
= CFTimeZoneCreateWithName(kCFAllocatorSystemDefault
, name
, false);
759 if (result
) return result
;
761 tzenv
= __CFgetenv("TZ");
763 CFStringRef name
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (uint8_t *)tzenv
, strlen(tzenv
), kCFStringEncodingUTF8
, false);
764 result
= CFTimeZoneCreateWithName(kCFAllocatorSystemDefault
, name
, true);
766 if (result
) return result
;
768 ret
= readlink(TZZONELINK
, linkbuf
, sizeof(linkbuf
));
772 if (strncmp(linkbuf
, TZZONEINFO
, sizeof(TZZONEINFO
) - 1) == 0) {
773 name
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (uint8_t *)linkbuf
+ sizeof(TZZONEINFO
) - 1, strlen(linkbuf
) - sizeof(TZZONEINFO
) + 1, kCFStringEncodingUTF8
, false);
775 name
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (uint8_t *)linkbuf
, strlen(linkbuf
), kCFStringEncodingUTF8
, false);
779 result
= CFTimeZoneCreateWithName(kCFAllocatorSystemDefault
, name
, false);
781 if (result
) return result
;
783 return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault
, 0.0);
786 CFTimeZoneRef
CFTimeZoneCopySystem(void) {
788 __CFTimeZoneLockGlobal();
789 if (NULL
== __CFTimeZoneSystem
) {
790 __CFTimeZoneUnlockGlobal();
791 tz
= __CFTimeZoneCreateSystem();
792 __CFTimeZoneLockGlobal();
793 if (NULL
== __CFTimeZoneSystem
) {
794 __CFTimeZoneSystem
= tz
;
796 if (tz
) CFRelease(tz
);
799 tz
= __CFTimeZoneSystem
? (CFTimeZoneRef
)CFRetain(__CFTimeZoneSystem
) : NULL
;
800 __CFTimeZoneUnlockGlobal();
804 static CFIndex __noteCount
= 0;
806 void CFTimeZoneResetSystem(void) {
807 __CFTimeZoneLockGlobal();
808 if (__CFTimeZoneDefault
== __CFTimeZoneSystem
) {
809 if (__CFTimeZoneDefault
) CFRelease(__CFTimeZoneDefault
);
810 __CFTimeZoneDefault
= NULL
;
812 CFTimeZoneRef tz
= __CFTimeZoneSystem
;
813 __CFTimeZoneSystem
= NULL
;
814 __CFTimeZoneUnlockGlobal();
815 if (tz
) CFRelease(tz
);
818 CFIndex
_CFTimeZoneGetNoteCount(void) {
822 CFTimeZoneRef
CFTimeZoneCopyDefault(void) {
824 __CFTimeZoneLockGlobal();
825 if (NULL
== __CFTimeZoneDefault
) {
826 __CFTimeZoneUnlockGlobal();
827 tz
= CFTimeZoneCopySystem();
828 __CFTimeZoneLockGlobal();
829 if (NULL
== __CFTimeZoneDefault
) {
830 __CFTimeZoneDefault
= tz
;
832 if (tz
) CFRelease(tz
);
835 tz
= __CFTimeZoneDefault
? (CFTimeZoneRef
)CFRetain(__CFTimeZoneDefault
) : NULL
;
836 __CFTimeZoneUnlockGlobal();
840 void CFTimeZoneSetDefault(CFTimeZoneRef tz
) {
841 if (tz
) __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
842 __CFTimeZoneLockGlobal();
843 if (tz
!= __CFTimeZoneDefault
) {
844 if (tz
) CFRetain(tz
);
845 if (__CFTimeZoneDefault
) CFRelease(__CFTimeZoneDefault
);
846 __CFTimeZoneDefault
= tz
;
848 __CFTimeZoneUnlockGlobal();
851 static CFDictionaryRef
__CFTimeZoneCopyCompatibilityDictionary(void);
853 CFArrayRef
CFTimeZoneCopyKnownNames(void) {
855 __CFTimeZoneLockGlobal();
856 if (NULL
== __CFKnownTimeZoneList
) {
857 CFMutableArrayRef list
;
858 /* TimeZone information locate in the registry for Win32
859 * (Aleksey Dukhnyakov)
861 list
= __CFCopyRecursiveDirectoryList();
862 // Remove undesirable ancient cruft
863 CFDictionaryRef dict
= __CFTimeZoneCopyCompatibilityDictionary();
865 for (idx
= CFArrayGetCount(list
); idx
--; ) {
866 CFStringRef item
= (CFStringRef
)CFArrayGetValueAtIndex(list
, idx
);
867 if (CFDictionaryContainsKey(dict
, item
)) {
868 CFArrayRemoveValueAtIndex(list
, idx
);
871 __CFKnownTimeZoneList
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, list
);
874 tzs
= __CFKnownTimeZoneList
? (CFArrayRef
)CFRetain(__CFKnownTimeZoneList
) : NULL
;
875 __CFTimeZoneUnlockGlobal();
879 /* The criteria here are sort of: coverage for the U.S. and Europe,
880 * large cities, abbreviation uniqueness, and perhaps a few others.
881 * But do not make the list too large with obscure information.
883 static const char *__CFTimeZoneAbbreviationDefaults
=
884 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
885 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
886 " <plist version=\"1.0\">"
888 " <key>ADT</key> <string>America/Halifax</string>"
889 " <key>AKDT</key> <string>America/Juneau</string>"
890 " <key>AKST</key> <string>America/Juneau</string>"
891 " <key>ART</key> <string>America/Argentina/Buenos_Aires</string>"
892 " <key>AST</key> <string>America/Halifax</string>"
893 " <key>BDT</key> <string>Asia/Dhaka</string>"
894 " <key>BRST</key> <string>America/Sao_Paulo</string>"
895 " <key>BRT</key> <string>America/Sao_Paulo</string>"
896 " <key>BST</key> <string>Europe/London</string>"
897 " <key>CAT</key> <string>Africa/Harare</string>"
898 " <key>CDT</key> <string>America/Chicago</string>"
899 " <key>CEST</key> <string>Europe/Paris</string>"
900 " <key>CET</key> <string>Europe/Paris</string>"
901 " <key>CLST</key> <string>America/Santiago</string>"
902 " <key>CLT</key> <string>America/Santiago</string>"
903 " <key>COT</key> <string>America/Bogota</string>"
904 " <key>CST</key> <string>America/Chicago</string>"
905 " <key>EAT</key> <string>Africa/Addis_Ababa</string>"
906 " <key>EDT</key> <string>America/New_York</string>"
907 " <key>EEST</key> <string>Europe/Istanbul</string>"
908 " <key>EET</key> <string>Europe/Istanbul</string>"
909 " <key>EST</key> <string>America/New_York</string>"
910 " <key>GMT</key> <string>GMT</string>"
911 " <key>GST</key> <string>Asia/Dubai</string>"
912 " <key>HKT</key> <string>Asia/Hong_Kong</string>"
913 " <key>HST</key> <string>Pacific/Honolulu</string>"
914 " <key>ICT</key> <string>Asia/Bangkok</string>"
915 " <key>IRST</key> <string>Asia/Tehran</string>"
916 " <key>IST</key> <string>Asia/Calcutta</string>"
917 " <key>JST</key> <string>Asia/Tokyo</string>"
918 " <key>KST</key> <string>Asia/Seoul</string>"
919 " <key>MDT</key> <string>America/Denver</string>"
920 " <key>MSD</key> <string>Europe/Moscow</string>"
921 " <key>MSK</key> <string>Europe/Moscow</string>"
922 " <key>MST</key> <string>America/Denver</string>"
923 " <key>NZDT</key> <string>Pacific/Auckland</string>"
924 " <key>NZST</key> <string>Pacific/Auckland</string>"
925 " <key>PDT</key> <string>America/Los_Angeles</string>"
926 " <key>PET</key> <string>America/Lima</string>"
927 " <key>PHT</key> <string>Asia/Manila</string>"
928 " <key>PKT</key> <string>Asia/Karachi</string>"
929 " <key>PST</key> <string>America/Los_Angeles</string>"
930 " <key>SGT</key> <string>Asia/Singapore</string>"
931 " <key>UTC</key> <string>UTC</string>"
932 " <key>WAT</key> <string>Africa/Lagos</string>"
933 " <key>WEST</key> <string>Europe/Lisbon</string>"
934 " <key>WET</key> <string>Europe/Lisbon</string>"
935 " <key>WIT</key> <string>Asia/Jakarta</string>"
939 CFDictionaryRef
CFTimeZoneCopyAbbreviationDictionary(void) {
940 CFDictionaryRef dict
;
941 __CFTimeZoneLockAbbreviations();
942 if (NULL
== __CFTimeZoneAbbreviationDict
) {
943 CFDataRef data
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)__CFTimeZoneAbbreviationDefaults
, strlen(__CFTimeZoneAbbreviationDefaults
));
944 __CFTimeZoneAbbreviationDict
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, data
, kCFPropertyListImmutable
, NULL
);
947 if (NULL
== __CFTimeZoneAbbreviationDict
) {
948 __CFTimeZoneAbbreviationDict
= CFDictionaryCreate(kCFAllocatorSystemDefault
, NULL
, NULL
, 0, NULL
, NULL
);
950 dict
= __CFTimeZoneAbbreviationDict
? (CFDictionaryRef
)CFRetain(__CFTimeZoneAbbreviationDict
) : NULL
;
951 __CFTimeZoneUnlockAbbreviations();
955 void _removeFromCache(const void *key
, const void *value
, void *context
) {
956 CFDictionaryRemoveValue(__CFTimeZoneCache
, (CFStringRef
)key
);
959 void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict
) {
960 __CFGenericValidateType(dict
, CFDictionaryGetTypeID());
961 __CFTimeZoneLockGlobal();
962 if (dict
!= __CFTimeZoneAbbreviationDict
) {
963 if (dict
) CFRetain(dict
);
964 if (__CFTimeZoneAbbreviationDict
) {
965 CFDictionaryApplyFunction(__CFTimeZoneAbbreviationDict
, _removeFromCache
, NULL
);
966 CFRelease(__CFTimeZoneAbbreviationDict
);
968 __CFTimeZoneAbbreviationDict
= dict
;
970 __CFTimeZoneUnlockGlobal();
973 CFTimeZoneRef
CFTimeZoneCreate(CFAllocatorRef allocator
, CFStringRef name
, CFDataRef data
) {
974 // assert: (NULL != name && NULL != data);
975 CFTimeZoneRef memory
;
977 CFTZPeriod
*tzp
= NULL
;
978 CFIndex idx
, cnt
= 0;
980 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
981 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
982 __CFGenericValidateType(name
, CFStringGetTypeID());
983 __CFGenericValidateType(data
, CFDataGetTypeID());
984 __CFTimeZoneLockGlobal();
985 if (NULL
!= __CFTimeZoneCache
&& CFDictionaryGetValueIfPresent(__CFTimeZoneCache
, name
, (const void **)&memory
)) {
986 __CFTimeZoneUnlockGlobal();
987 return (CFTimeZoneRef
)CFRetain(memory
);
989 if (!__CFParseTimeZoneData(allocator
, data
, &tzp
, &cnt
)) {
990 __CFTimeZoneUnlockGlobal();
993 size
= sizeof(struct __CFTimeZone
) - sizeof(CFRuntimeBase
);
994 memory
= (CFTimeZoneRef
)_CFRuntimeCreateInstance(allocator
, CFTimeZoneGetTypeID(), size
, NULL
);
995 if (NULL
== memory
) {
996 __CFTimeZoneUnlockGlobal();
997 for (idx
= 0; idx
< cnt
; idx
++) {
998 if (NULL
!= tzp
[idx
].abbrev
) CFRelease(tzp
[idx
].abbrev
);
1000 if (NULL
!= tzp
) CFAllocatorDeallocate(allocator
, tzp
);
1003 ((struct __CFTimeZone
*)memory
)->_name
= (CFStringRef
)CFStringCreateCopy(allocator
, name
);
1004 ((struct __CFTimeZone
*)memory
)->_data
= CFDataCreateCopy(allocator
, data
);
1005 ((struct __CFTimeZone
*)memory
)->_periods
= tzp
;
1006 ((struct __CFTimeZone
*)memory
)->_periodCnt
= cnt
;
1007 if (NULL
== __CFTimeZoneCache
) {
1008 __CFTimeZoneCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1010 CFDictionaryAddValue(__CFTimeZoneCache
, ((struct __CFTimeZone
*)memory
)->_name
, memory
);
1011 __CFTimeZoneUnlockGlobal();
1015 static CFTimeZoneRef
__CFTimeZoneCreateFixed(CFAllocatorRef allocator
, int32_t seconds
, CFStringRef name
, int isDST
) {
1016 CFTimeZoneRef result
;
1018 int32_t nameLen
= CFStringGetLength(name
);
1019 unsigned char dataBytes
[52 + nameLen
+ 1];
1020 memset(dataBytes
, 0, sizeof(dataBytes
));
1022 // Put in correct magic bytes for timezone structures
1028 __CFEntzcode(1, dataBytes
+ 20);
1029 __CFEntzcode(1, dataBytes
+ 24);
1030 __CFEntzcode(1, dataBytes
+ 36);
1031 __CFEntzcode(nameLen
+ 1, dataBytes
+ 40);
1032 __CFEntzcode(seconds
, dataBytes
+ 44);
1033 dataBytes
[48] = isDST
? 1 : 0;
1034 CFStringGetCString(name
, (char *)dataBytes
+ 50, nameLen
+ 1, kCFStringEncodingASCII
);
1035 data
= CFDataCreate(allocator
, dataBytes
, 52 + nameLen
+ 1);
1036 result
= CFTimeZoneCreate(allocator
, name
, data
);
1042 // rounds offset to nearest minute
1043 CFTimeZoneRef
CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator
, CFTimeInterval ti
) {
1044 CFTimeZoneRef result
;
1046 int32_t seconds
, minute
, hour
;
1047 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
1048 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
1049 if (ti
< -18.0 * 3600 || 18.0 * 3600 < ti
) return NULL
;
1050 ti
= (ti
< 0.0) ? ceil((ti
/ 60.0) - 0.5) * 60.0 : floor((ti
/ 60.0) + 0.5) * 60.0;
1051 seconds
= (int32_t)ti
;
1052 hour
= (ti
< 0) ? (-seconds
/ 3600) : (seconds
/ 3600);
1053 seconds
-= ((ti
< 0) ? -hour
: hour
) * 3600;
1054 minute
= (ti
< 0) ? (-seconds
/ 60) : (seconds
/ 60);
1055 if (fabs(ti
) < 1.0) {
1056 name
= (CFStringRef
)CFRetain(CFSTR("GMT"));
1058 name
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("GMT%c%02d%02d"), (ti
< 0.0 ? '-' : '+'), hour
, minute
);
1060 result
= __CFTimeZoneCreateFixed(allocator
, (int32_t)ti
, name
, 0);
1065 CFTimeZoneRef
CFTimeZoneCreateWithName(CFAllocatorRef allocator
, CFStringRef name
, Boolean tryAbbrev
) {
1066 CFTimeZoneRef result
= NULL
;
1067 CFStringRef tzName
= NULL
;
1068 CFDataRef data
= NULL
;
1070 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
1071 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
1072 __CFGenericValidateType(name
, CFStringGetTypeID());
1073 if (CFEqual(CFSTR(""), name
)) {
1074 // empty string is not a time zone name, just abort now,
1075 // following stuff will fail anyway
1078 __CFTimeZoneLockGlobal();
1079 if (NULL
!= __CFTimeZoneCache
&& CFDictionaryGetValueIfPresent(__CFTimeZoneCache
, name
, (const void **)&result
)) {
1080 __CFTimeZoneUnlockGlobal();
1081 return (CFTimeZoneRef
)CFRetain(result
);
1083 __CFTimeZoneUnlockGlobal();
1084 CFIndex len
= CFStringGetLength(name
);
1085 if (6 == len
|| 8 == len
) {
1087 CFStringGetCharacters(name
, CFRangeMake(0, len
), buffer
);
1088 if ('G' == buffer
[0] && 'M' == buffer
[1] && 'T' == buffer
[2] && ('+' == buffer
[3] || '-' == buffer
[3])) {
1089 if (('0' <= buffer
[4] && buffer
[4] <= '9') && ('0' <= buffer
[5] && buffer
[5] <= '9')) {
1090 int32_t hours
= (buffer
[4] - '0') * 10 + (buffer
[5] - '0');
1091 if (-14 <= hours
&& hours
<= 14) {
1092 CFTimeInterval ti
= hours
* 3600.0;
1094 return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator
, ('-' == buffer
[3] ? -1.0 : 1.0) * ti
);
1096 if (('0' <= buffer
[6] && buffer
[6] <= '9') && ('0' <= buffer
[7] && buffer
[7] <= '9')) {
1097 int32_t minutes
= (buffer
[6] - '0') * 10 + (buffer
[7] - '0');
1098 if ((-14 == hours
&& 0 == minutes
) || (14 == hours
&& 0 == minutes
) || (0 <= minutes
&& minutes
<= 59)) {
1099 ti
= ti
+ minutes
* 60.0;
1100 return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator
, ('-' == buffer
[3] ? -1.0 : 1.0) * ti
);
1108 CFURLRef baseURL
, tempURL
;
1112 #if DEPLOYMENT_TARGET_WINDOWS
1113 if (!__tzZoneInfo
) __InitTZStrings();
1114 if (!__tzZoneInfo
) return NULL
;
1115 baseURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, __tzZoneInfo
, kCFURLWindowsPathStyle
, true);
1117 baseURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, CFSTR(TZZONEINFO
), kCFURLPOSIXPathStyle
, true);
1120 CFDictionaryRef abbrevs
= CFTimeZoneCopyAbbreviationDictionary();
1121 tzName
= CFDictionaryGetValue(abbrevs
, name
);
1122 if (NULL
!= tzName
) {
1123 tempURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault
, baseURL
, tzName
, false);
1124 if (NULL
!= tempURL
) {
1125 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault
, tempURL
, &bytes
, &length
, 0, 0)) {
1126 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, bytes
, length
, kCFAllocatorSystemDefault
);
1134 CFDictionaryRef dict
= __CFTimeZoneCopyCompatibilityDictionary();
1135 CFStringRef mapping
= CFDictionaryGetValue(dict
, name
);
1138 #if DEPLOYMENT_TARGET_WINDOWS
1139 } else if (CFStringHasPrefix(name
, __tzZoneInfo
)) {
1140 CFMutableStringRef unprefixed
= CFStringCreateMutableCopy(kCFAllocatorSystemDefault
, CFStringGetLength(name
), name
);
1141 CFStringDelete(unprefixed
, CFRangeMake(0, CFStringGetLength(__tzZoneInfo
)));
1143 } else if (CFStringHasPrefix(name
, CFSTR(TZZONEINFO
))) {
1144 CFMutableStringRef unprefixed
= CFStringCreateMutableCopy(kCFAllocatorSystemDefault
, CFStringGetLength(name
), name
);
1145 CFStringDelete(unprefixed
, CFRangeMake(0, sizeof(TZZONEINFO
)));
1147 mapping
= CFDictionaryGetValue(dict
, unprefixed
);
1151 CFRelease(unprefixed
);
1154 if (CFEqual(CFSTR(""), name
)) {
1160 tempURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault
, baseURL
, tzName
, false);
1161 if (NULL
!= tempURL
) {
1162 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault
, tempURL
, &bytes
, &length
, 0, 0)) {
1163 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, bytes
, length
, kCFAllocatorSystemDefault
);
1170 result
= CFTimeZoneCreate(allocator
, tzName
, data
);
1171 if (name
!= tzName
) {
1172 CFStringRef nameCopy
= (CFStringRef
)CFStringCreateCopy(allocator
, name
);
1173 __CFTimeZoneLockGlobal();
1174 CFDictionaryAddValue(__CFTimeZoneCache
, nameCopy
, result
);
1175 __CFTimeZoneUnlockGlobal();
1176 CFRelease(nameCopy
);
1183 CFStringRef
CFTimeZoneGetName(CFTimeZoneRef tz
) {
1184 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFStringRef
, (NSTimeZone
*)tz
, name
);
1185 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1189 CFDataRef
CFTimeZoneGetData(CFTimeZoneRef tz
) {
1190 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFDataRef
, (NSTimeZone
*)tz
, data
);
1191 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1195 /* This function converts CFAbsoluteTime to (Win32) SYSTEMTIME
1196 * (Aleksey Dukhnyakov)
1198 #if DEPLOYMENT_TARGET_WINDOWS
1199 BOOL
__CFTimeZoneGetWin32SystemTime(SYSTEMTIME
* sys_time
, CFAbsoluteTime time
)
1202 FILETIME
* ftime
=(FILETIME
*)&l
;
1204 /* seconds between 1601 and 1970 : 11644473600,
1205 * seconds between 1970 and 2001 : 978307200,
1206 * FILETIME - number of 100-nanosecond intervals since January 1, 1601
1208 l
=(LONGLONG
)(time
+11644473600LL+978307200)*10000000;
1209 if (FileTimeToSystemTime(ftime
,sys_time
))
1216 CFTimeInterval
CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1218 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1219 idx
= __CFBSearchTZPeriods(tz
, at
);
1220 return __CFTZPeriodGMTOffset(&(tz
->_periods
[idx
]));
1223 CFStringRef
CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1226 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1227 idx
= __CFBSearchTZPeriods(tz
, at
);
1228 result
= __CFTZPeriodAbbreviation(&(tz
->_periods
[idx
]));
1229 return result
? (CFStringRef
)CFRetain(result
) : NULL
;
1232 Boolean
CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1234 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1235 idx
= __CFBSearchTZPeriods(tz
, at
);
1236 return __CFTZPeriodIsDST(&(tz
->_periods
[idx
]));
1239 CFTimeInterval
CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1240 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFTimeInterval
, (NSTimeZone
*)tz
, _daylightSavingTimeOffsetForAbsoluteTime
:at
);
1241 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1242 CFIndex idx
= __CFBSearchTZPeriods(tz
, at
);
1243 if (__CFTZPeriodIsDST(&(tz
->_periods
[idx
]))) {
1244 CFTimeInterval offset
= __CFTZPeriodGMTOffset(&(tz
->_periods
[idx
]));
1245 if (idx
+ 1 < tz
->_periodCnt
) {
1246 return offset
- __CFTZPeriodGMTOffset(&(tz
->_periods
[idx
+ 1]));
1247 } else if (0 < idx
) {
1248 return offset
- __CFTZPeriodGMTOffset(&(tz
->_periods
[idx
- 1]));
1254 CFAbsoluteTime
CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1255 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFTimeInterval
, (NSTimeZone
*)tz
, _nextDaylightSavingTimeTransitionAfterAbsoluteTime
:at
);
1256 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1257 CFIndex idx
= __CFBSearchTZPeriods(tz
, at
);
1258 if (tz
->_periodCnt
<= idx
+ 1) {
1261 return (CFAbsoluteTime
)__CFTZPeriodStartSeconds(&(tz
->_periods
[idx
+ 1]));
1264 extern UCalendar
*__CFCalendarCreateUCalendar(CFStringRef calendarID
, CFStringRef localeID
, CFTimeZoneRef tz
);
1266 #define BUFFER_SIZE 768
1268 CFStringRef
CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz
, CFTimeZoneNameStyle style
, CFLocaleRef locale
) {
1269 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFStringRef
, (NSTimeZone
*)tz
, localizedName
:(NSTimeZoneNameStyle
)style locale
:(NSLocale
*)locale
);
1270 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1271 __CFGenericValidateType(locale
, CFLocaleGetTypeID());
1273 if (style
== kCFTimeZoneNameStyleGeneric
|| style
== kCFTimeZoneNameStyleShortGeneric
) {
1274 CFDateFormatterRef df
= CFDateFormatterCreate(kCFAllocatorSystemDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
);
1275 CFDateFormatterSetProperty(df
, kCFDateFormatterTimeZone
, tz
);
1276 CFDateFormatterSetFormat(df
, (style
== kCFTimeZoneNameStyleGeneric
) ? CFSTR("vvvv") : CFSTR("v"));
1277 CFStringRef str
= CFDateFormatterCreateStringWithAbsoluteTime(CFGetAllocator(tz
), df
, 0.0);
1282 CFStringRef localeID
= CFLocaleGetIdentifier(locale
);
1283 UCalendar
*cal
= __CFCalendarCreateUCalendar(NULL
, localeID
, tz
);
1288 char buffer
[BUFFER_SIZE
];
1289 const char *cstr
= CFStringGetCStringPtr(localeID
, kCFStringEncodingASCII
);
1291 if (CFStringGetCString(localeID
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
1298 UChar ubuffer
[BUFFER_SIZE
];
1299 UErrorCode status
= U_ZERO_ERROR
;
1300 int32_t cnt
= ucal_getTimeZoneDisplayName(cal
, (UCalendarDisplayNameType
)style
, cstr
, ubuffer
, BUFFER_SIZE
, &status
);
1302 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1303 return CFStringCreateWithCharacters(CFGetAllocator(tz
), (const UniChar
*)ubuffer
, cnt
);
1308 static CFDictionaryRef
__CFTimeZoneCopyCompatibilityDictionary(void) {
1309 CFDictionaryRef dict
;
1310 __CFTimeZoneLockCompatibilityMapping();
1311 if (NULL
== __CFTimeZoneCompatibilityMappingDict
) {
1312 __CFTimeZoneCompatibilityMappingDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 112, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1314 // Empty string means delete/ignore these
1316 dict
= __CFTimeZoneCompatibilityMappingDict
? (CFDictionaryRef
)CFRetain(__CFTimeZoneCompatibilityMappingDict
) : NULL
;
1317 __CFTimeZoneUnlockCompatibilityMapping();