2 * Copyright (c) 2008 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@
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include <CoreFoundation/CFTimeZone.h>
29 #include <CoreFoundation/CFPropertyList.h>
31 #include "CFInternal.h"
38 #include <unicode/ucal.h>
39 #if DEPLOYMENT_TARGET_MACOSX
42 #include <sys/fcntl.h>
46 #if DEPLOYMENT_TARGET_MACOSX
47 #define TZZONELINK TZDEFAULT
48 #define TZZONEINFO TZDIR "/"
51 CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification
, "kCFTimeZoneSystemTimeZoneDidChangeNotification")
53 static CFTimeZoneRef __CFTimeZoneSystem
= NULL
;
54 static CFTimeZoneRef __CFTimeZoneDefault
= NULL
;
55 static CFDictionaryRef __CFTimeZoneAbbreviationDict
= NULL
;
56 static CFSpinLock_t __CFTimeZoneAbbreviationLock
= CFSpinLockInit
;
57 static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict
= NULL
;
58 static CFSpinLock_t __CFTimeZoneCompatibilityMappingLock
= CFSpinLockInit
;
59 static CFArrayRef __CFKnownTimeZoneList
= NULL
;
60 static CFMutableDictionaryRef __CFTimeZoneCache
= NULL
;
61 static CFSpinLock_t __CFTimeZoneGlobalLock
= CFSpinLockInit
;
63 CF_INLINE
void __CFTimeZoneLockGlobal(void) {
64 __CFSpinLock(&__CFTimeZoneGlobalLock
);
67 CF_INLINE
void __CFTimeZoneUnlockGlobal(void) {
68 __CFSpinUnlock(&__CFTimeZoneGlobalLock
);
71 CF_INLINE
void __CFTimeZoneLockAbbreviations(void) {
72 __CFSpinLock(&__CFTimeZoneAbbreviationLock
);
75 CF_INLINE
void __CFTimeZoneUnlockAbbreviations(void) {
76 __CFSpinUnlock(&__CFTimeZoneAbbreviationLock
);
79 CF_INLINE
void __CFTimeZoneLockCompatibilityMapping(void) {
80 __CFSpinLock(&__CFTimeZoneCompatibilityMappingLock
);
83 CF_INLINE
void __CFTimeZoneUnlockCompatibilityMapping(void) {
84 __CFSpinUnlock(&__CFTimeZoneCompatibilityMappingLock
);
87 #if DEPLOYMENT_TARGET_MACOSX
88 static CFMutableArrayRef
__CFCopyRecursiveDirectoryList() {
89 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
90 int fd
= open(TZDIR
"/zone.tab", O_RDONLY
);
93 ssize_t len
= read(fd
, buffer
, sizeof(buffer
));
95 if (len
< sizeof(buffer
)) {
96 // assumes that partial read only occurs at the end of the file
100 const uint8_t *bytes
= buffer
;
102 const uint8_t *nextl
= memchr(bytes
, '\n', len
);
106 len
-= (nextl
- bytes
);
110 const uint8_t *tab1
= memchr(bytes
, '\t', (nextl
- bytes
));
112 len
-= (nextl
- bytes
);
117 len
-= (tab1
- bytes
);
119 const uint8_t *tab2
= memchr(bytes
, '\t', (nextl
- bytes
));
121 len
-= (nextl
- bytes
);
126 len
-= (tab2
- bytes
);
128 const uint8_t *tab3
= memchr(bytes
, '\t', (nextl
- bytes
));
129 int nmlen
= tab3
? (tab3
- bytes
) : (nextl
- 1 - bytes
);
130 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, bytes
, nmlen
, kCFStringEncodingUTF8
, false);
131 CFArrayAppendValue(result
, string
);
133 len
-= (nextl
- bytes
);
136 lseek(fd
, -len
, SEEK_CUR
);
142 #error Unknown or unspecified DEPLOYMENT_TARGET
145 typedef struct _CFTZPeriod
{
151 struct __CFTimeZone
{
153 CFStringRef _name
; /* immutable */
154 CFDataRef _data
; /* immutable */
155 CFTZPeriod
*_periods
; /* immutable */
156 int32_t _periodCnt
; /* immutable */
159 /* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates
160 * between 1933 and 2069; info outside these years is discarded on read-in */
161 /* Bits 31-18 of the info are unused */
162 /* Bit 17 of the info is used for the is-DST state */
163 /* Bit 16 of the info is used for the sign of the offset (1 == negative) */
164 /* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */
166 CF_INLINE
void __CFTZPeriodInit(CFTZPeriod
*period
, int32_t startTime
, CFStringRef abbrev
, int32_t offset
, Boolean isDST
) {
167 period
->startSec
= startTime
;
168 period
->abbrev
= abbrev
? (CFStringRef
)CFRetain(abbrev
) : NULL
;
169 __CFBitfieldSetValue(period
->info
, 15, 0, abs(offset
));
170 __CFBitfieldSetValue(period
->info
, 16, 16, (offset
< 0 ? 1 : 0));
171 __CFBitfieldSetValue(period
->info
, 17, 17, (isDST
? 1 : 0));
174 CF_INLINE
int32_t __CFTZPeriodStartSeconds(const CFTZPeriod
*period
) {
175 return period
->startSec
;
178 CF_INLINE CFStringRef
__CFTZPeriodAbbreviation(const CFTZPeriod
*period
) {
179 return period
->abbrev
;
182 CF_INLINE
int32_t __CFTZPeriodGMTOffset(const CFTZPeriod
*period
) {
183 int32_t v
= __CFBitfieldGetValue(period
->info
, 15, 0);
184 if (__CFBitfieldGetValue(period
->info
, 16, 16)) v
= -v
;
188 CF_INLINE Boolean
__CFTZPeriodIsDST(const CFTZPeriod
*period
) {
189 return (Boolean
)__CFBitfieldGetValue(period
->info
, 17, 17);
192 static CFComparisonResult
__CFCompareTZPeriods(const void *val1
, const void *val2
, void *context
) {
193 CFTZPeriod
*tzp1
= (CFTZPeriod
*)val1
;
194 CFTZPeriod
*tzp2
= (CFTZPeriod
*)val2
;
195 // we treat equal as less than, as the code which uses the
196 // result of the bsearch doesn't expect exact matches
197 // (they're pretty rare, so no point in over-coding for them)
198 if (__CFTZPeriodStartSeconds(tzp1
) <= __CFTZPeriodStartSeconds(tzp2
)) return kCFCompareLessThan
;
199 return kCFCompareGreaterThan
;
202 static CFIndex
__CFBSearchTZPeriods(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
204 __CFTZPeriodInit(&elem
, (int32_t)floor(at
), NULL
, 0, false);
205 CFIndex idx
= CFBSearch(&elem
, sizeof(CFTZPeriod
), tz
->_periods
, tz
->_periodCnt
, __CFCompareTZPeriods
, NULL
);
206 if (tz
->_periodCnt
<= idx
) {
207 idx
= tz
->_periodCnt
;
208 } else if (0 == idx
) {
215 CF_INLINE
int32_t __CFDetzcode(const unsigned char *bufp
) {
216 int32_t result
= (bufp
[0] & 0x80) ? ~0L : 0L;
217 result
= (result
<< 8) | (bufp
[0] & 0xff);
218 result
= (result
<< 8) | (bufp
[1] & 0xff);
219 result
= (result
<< 8) | (bufp
[2] & 0xff);
220 result
= (result
<< 8) | (bufp
[3] & 0xff);
224 CF_INLINE
void __CFEntzcode(int32_t value
, unsigned char *bufp
) {
225 bufp
[0] = (value
>> 24) & 0xff;
226 bufp
[1] = (value
>> 16) & 0xff;
227 bufp
[2] = (value
>> 8) & 0xff;
228 bufp
[3] = (value
>> 0) & 0xff;
231 #if DEPLOYMENT_TARGET_MACOSX
232 static Boolean
__CFParseTimeZoneData(CFAllocatorRef allocator
, CFDataRef data
, CFTZPeriod
**tzpp
, CFIndex
*cntp
) {
233 int32_t len
, timecnt
, typecnt
, charcnt
, idx
, cnt
;
234 const uint8_t *p
, *timep
, *typep
, *ttisp
, *charp
;
236 Boolean result
= true;
238 p
= CFDataGetBytePtr(data
);
239 len
= CFDataGetLength(data
);
240 if (len
< (int32_t)sizeof(struct tzhead
)) {
244 if (!(p
[0] == 'T' && p
[1] == 'Z' && p
[2] == 'i' && p
[3] == 'f')) return false; /* Don't parse without TZif at head of file */
246 p
+= 20 + 4 + 4 + 4; /* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */
247 timecnt
= __CFDetzcode(p
);
249 typecnt
= __CFDetzcode(p
);
251 charcnt
= __CFDetzcode(p
);
253 if (typecnt
<= 0 || timecnt
< 0 || charcnt
< 0) {
256 if (1024 < timecnt
|| 32 < typecnt
|| 128 < charcnt
) {
257 // reject excessive timezones to avoid arithmetic overflows for
258 // security reasons and to reject potentially corrupt files
261 if (len
- (int32_t)sizeof(struct tzhead
) < (4 + 1) * timecnt
+ (4 + 1 + 1) * typecnt
+ charcnt
) {
265 typep
= timep
+ 4 * timecnt
;
266 ttisp
= typep
+ timecnt
;
267 charp
= ttisp
+ (4 + 1 + 1) * typecnt
;
268 cnt
= (0 < timecnt
) ? timecnt
: 1;
269 *tzpp
= CFAllocatorAllocate(allocator
, cnt
* sizeof(CFTZPeriod
), 0);
270 if (__CFOASafe
) __CFSetLastAllocationEventName(*tzpp
, "CFTimeZone (store)");
271 memset(*tzpp
, 0, cnt
* sizeof(CFTZPeriod
));
272 abbrs
= CFAllocatorAllocate(allocator
, (charcnt
+ 1) * sizeof(CFStringRef
), 0);
273 if (__CFOASafe
) __CFSetLastAllocationEventName(abbrs
, "CFTimeZone (temp)");
274 for (idx
= 0; idx
< charcnt
+ 1; idx
++) {
277 for (idx
= 0; idx
< cnt
; idx
++) {
279 int32_t itime
, offset
;
280 uint8_t type
, dst
, abbridx
;
282 at
= (CFAbsoluteTime
)(__CFDetzcode(timep
) + 0.0) - kCFAbsoluteTimeIntervalSince1970
;
283 if (0 == timecnt
) itime
= INT_MIN
;
284 else if (at
< (CFAbsoluteTime
)INT_MIN
) itime
= INT_MIN
;
285 else if ((CFAbsoluteTime
)INT_MAX
< at
) itime
= INT_MAX
;
286 else itime
= (int32_t)at
;
287 timep
+= 4; /* harmless if 0 == timecnt */
288 type
= (0 < timecnt
) ? (uint8_t)*typep
++ : 0;
289 if (typecnt
<= type
) {
293 offset
= __CFDetzcode(ttisp
+ 6 * type
);
294 dst
= (uint8_t)*(ttisp
+ 6 * type
+ 4);
295 if (0 != dst
&& 1 != dst
) {
299 abbridx
= (uint8_t)*(ttisp
+ 6 * type
+ 5);
300 if (charcnt
< abbridx
) {
304 if (NULL
== abbrs
[abbridx
]) {
305 abbrs
[abbridx
] = CFStringCreateWithCString(allocator
, (char *)&charp
[abbridx
], kCFStringEncodingASCII
);
307 __CFTZPeriodInit(*tzpp
+ idx
, itime
, abbrs
[abbridx
], offset
, (dst
? true : false));
309 for (idx
= 0; idx
< charcnt
+ 1; idx
++) {
310 if (NULL
!= abbrs
[idx
]) {
311 CFRelease(abbrs
[idx
]);
314 CFAllocatorDeallocate(allocator
, abbrs
);
316 // dump all but the last INT_MIN and the first INT_MAX
317 for (idx
= 0; idx
< cnt
; idx
++) {
318 if (((*tzpp
+ idx
)->startSec
== INT_MIN
) && (idx
+ 1 < cnt
) && (((*tzpp
+ idx
+ 1)->startSec
== INT_MIN
))) {
319 if (NULL
!= (*tzpp
+ idx
)->abbrev
) CFRelease((*tzpp
+ idx
)->abbrev
);
321 memmove((*tzpp
+ idx
), (*tzpp
+ idx
+ 1), sizeof(CFTZPeriod
) * (cnt
- idx
));
325 // Don't combine these loops! Watch the idx decrementing...
326 for (idx
= 0; idx
< cnt
; idx
++) {
327 if (((*tzpp
+ idx
)->startSec
== INT_MAX
) && (0 < idx
) && (((*tzpp
+ idx
- 1)->startSec
== INT_MAX
))) {
328 if (NULL
!= (*tzpp
+ idx
)->abbrev
) CFRelease((*tzpp
+ idx
)->abbrev
);
330 memmove((*tzpp
+ idx
), (*tzpp
+ idx
+ 1), sizeof(CFTZPeriod
) * (cnt
- idx
));
334 CFQSortArray(*tzpp
, cnt
, sizeof(CFTZPeriod
), __CFCompareTZPeriods
, NULL
);
335 // if the first period is in DST and there is more than one period, drop it
336 if (1 < cnt
&& __CFTZPeriodIsDST(*tzpp
+ 0)) {
337 if (NULL
!= (*tzpp
+ 0)->abbrev
) CFRelease((*tzpp
+ 0)->abbrev
);
339 memmove((*tzpp
+ 0), (*tzpp
+ 0 + 1), sizeof(CFTZPeriod
) * (cnt
- 0));
343 CFAllocatorDeallocate(allocator
, *tzpp
);
349 static Boolean
__CFParseTimeZoneData(CFAllocatorRef allocator
, CFDataRef data
, CFTZPeriod
**tzpp
, CFIndex
*cntp
) {
350 /* We use Win32 function to find TimeZone
351 * (Aleksey Dukhnyakov)
353 *tzpp
= (CFTZPeriod
*)CFAllocatorAllocate(allocator
, sizeof(CFTZPeriod
), 0);
354 memset(*tzpp
, 0, sizeof(CFTZPeriod
));
355 __CFTZPeriodInit(*tzpp
, 0, NULL
, 0, false);
360 #error Unknown or unspecified DEPLOYMENT_TARGET
363 static Boolean
__CFTimeZoneEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
364 CFTimeZoneRef tz1
= (CFTimeZoneRef
)cf1
;
365 CFTimeZoneRef tz2
= (CFTimeZoneRef
)cf2
;
366 if (!CFEqual(CFTimeZoneGetName(tz1
), CFTimeZoneGetName(tz2
))) return false;
367 if (!CFEqual(CFTimeZoneGetData(tz1
), CFTimeZoneGetData(tz2
))) return false;
371 static CFHashCode
__CFTimeZoneHash(CFTypeRef cf
) {
372 CFTimeZoneRef tz
= (CFTimeZoneRef
)cf
;
373 return CFHash(CFTimeZoneGetName(tz
));
376 static CFStringRef
__CFTimeZoneCopyDescription(CFTypeRef cf
) {
377 CFTimeZoneRef tz
= (CFTimeZoneRef
)cf
;
378 CFStringRef result
, abbrev
;
380 at
= CFAbsoluteTimeGetCurrent();
381 abbrev
= CFTimeZoneCopyAbbreviation(tz
, at
);
382 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");
387 static void __CFTimeZoneDeallocate(CFTypeRef cf
) {
388 CFTimeZoneRef tz
= (CFTimeZoneRef
)cf
;
389 CFAllocatorRef allocator
= CFGetAllocator(tz
);
391 if (tz
->_name
) CFRelease(tz
->_name
);
392 if (tz
->_data
) CFRelease(tz
->_data
);
393 for (idx
= 0; idx
< tz
->_periodCnt
; idx
++) {
394 if (NULL
!= tz
->_periods
[idx
].abbrev
) CFRelease(tz
->_periods
[idx
].abbrev
);
396 if (NULL
!= tz
->_periods
) CFAllocatorDeallocate(allocator
, tz
->_periods
);
399 static CFTypeID __kCFTimeZoneTypeID
= _kCFRuntimeNotATypeID
;
401 static const CFRuntimeClass __CFTimeZoneClass
= {
406 __CFTimeZoneDeallocate
,
410 __CFTimeZoneCopyDescription
413 __private_extern__
void __CFTimeZoneInitialize(void) {
414 __kCFTimeZoneTypeID
= _CFRuntimeRegisterClass(&__CFTimeZoneClass
);
417 CFTypeID
CFTimeZoneGetTypeID(void) {
418 return __kCFTimeZoneTypeID
;
422 #if DEPLOYMENT_TARGET_MACOSX
423 static CFTimeZoneRef
__CFTimeZoneCreateSystem(void) {
424 CFTimeZoneRef result
= NULL
;
429 char linkbuf
[CFMaxPathSize
];
431 tzenv
= getenv("TZFILE");
433 CFStringRef name
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (uint8_t *)tzenv
, strlen(tzenv
), kCFStringEncodingUTF8
, false);
434 result
= CFTimeZoneCreateWithName(kCFAllocatorSystemDefault
, name
, false);
436 if (result
) return result
;
438 tzenv
= getenv("TZ");
440 CFStringRef name
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (uint8_t *)tzenv
, strlen(tzenv
), kCFStringEncodingUTF8
, false);
441 result
= CFTimeZoneCreateWithName(kCFAllocatorSystemDefault
, name
, true);
443 if (result
) return result
;
445 ret
= readlink(TZZONELINK
, linkbuf
, sizeof(linkbuf
));
449 if (strncmp(linkbuf
, TZZONEINFO
, sizeof(TZZONEINFO
) - 1) == 0) {
450 name
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (uint8_t *)linkbuf
+ sizeof(TZZONEINFO
) - 1, strlen(linkbuf
) - sizeof(TZZONEINFO
) + 1, kCFStringEncodingUTF8
, false);
452 name
= CFStringCreateWithBytes(kCFAllocatorSystemDefault
, (uint8_t *)linkbuf
, strlen(linkbuf
), kCFStringEncodingUTF8
, false);
454 result
= CFTimeZoneCreateWithName(kCFAllocatorSystemDefault
, name
, false);
456 if (result
) return result
;
458 return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault
, 0.0);
461 static CFTimeZoneRef
__CFTimeZoneCreateSystem(void) {
462 CFTimeZoneRef result
= NULL
;
463 /* The GetTimeZoneInformation function retrieves the current
464 * time-zone parameters for Win32
465 * (Aleksey Dukhnyakov)
468 TIME_ZONE_INFORMATION tz
;
470 dw_result
=GetTimeZoneInformation(&tz
);
472 if ( dw_result
== TIME_ZONE_ID_STANDARD
||
473 dw_result
== TIME_ZONE_ID_DAYLIGHT
) {
474 CFStringRef name
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)tz
.StandardName
, wcslen(tz
.StandardName
));
475 data
= CFDataCreate(kCFAllocatorSystemDefault
, (UInt8
*)&tz
, sizeof(tz
));
476 result
= CFTimeZoneCreate(kCFAllocatorSystemDefault
, name
, data
);
479 if (result
) return result
;
481 return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault
, 0.0);
484 #error Unknown or unspecified DEPLOYMENT_TARGET
487 CFTimeZoneRef
CFTimeZoneCopySystem(void) {
489 __CFTimeZoneLockGlobal();
490 if (NULL
== __CFTimeZoneSystem
) {
491 __CFTimeZoneUnlockGlobal();
492 tz
= __CFTimeZoneCreateSystem();
493 __CFTimeZoneLockGlobal();
494 if (NULL
== __CFTimeZoneSystem
) {
495 __CFTimeZoneSystem
= tz
;
497 if (tz
) CFRelease(tz
);
500 tz
= __CFTimeZoneSystem
? (CFTimeZoneRef
)CFRetain(__CFTimeZoneSystem
) : NULL
;
501 __CFTimeZoneUnlockGlobal();
505 static CFIndex __noteCount
= 0;
507 void CFTimeZoneResetSystem(void) {
508 __CFTimeZoneLockGlobal();
509 if (__CFTimeZoneDefault
== __CFTimeZoneSystem
) {
510 if (__CFTimeZoneDefault
) CFRelease(__CFTimeZoneDefault
);
511 __CFTimeZoneDefault
= NULL
;
513 CFTimeZoneRef tz
= __CFTimeZoneSystem
;
514 __CFTimeZoneSystem
= NULL
;
515 __CFTimeZoneUnlockGlobal();
516 if (tz
) CFRelease(tz
);
519 CFIndex
_CFTimeZoneGetNoteCount(void) {
523 CFTimeZoneRef
CFTimeZoneCopyDefault(void) {
525 __CFTimeZoneLockGlobal();
526 if (NULL
== __CFTimeZoneDefault
) {
527 __CFTimeZoneUnlockGlobal();
528 tz
= CFTimeZoneCopySystem();
529 __CFTimeZoneLockGlobal();
530 if (NULL
== __CFTimeZoneDefault
) {
531 __CFTimeZoneDefault
= tz
;
533 if (tz
) CFRelease(tz
);
536 tz
= __CFTimeZoneDefault
? (CFTimeZoneRef
)CFRetain(__CFTimeZoneDefault
) : NULL
;
537 __CFTimeZoneUnlockGlobal();
541 void CFTimeZoneSetDefault(CFTimeZoneRef tz
) {
542 if (tz
) __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
543 __CFTimeZoneLockGlobal();
544 if (tz
!= __CFTimeZoneDefault
) {
545 if (tz
) CFRetain(tz
);
546 if (__CFTimeZoneDefault
) CFRelease(__CFTimeZoneDefault
);
547 __CFTimeZoneDefault
= tz
;
549 __CFTimeZoneUnlockGlobal();
552 static CFDictionaryRef
__CFTimeZoneCopyCompatibilityDictionary(void);
554 CFArrayRef
CFTimeZoneCopyKnownNames(void) {
556 __CFTimeZoneLockGlobal();
557 if (NULL
== __CFKnownTimeZoneList
) {
558 CFMutableArrayRef list
;
559 /* TimeZone information locate in the registry for Win32
560 * (Aleksey Dukhnyakov)
562 #if DEPLOYMENT_TARGET_MACOSX
563 list
= __CFCopyRecursiveDirectoryList();
565 #error Unknown or unspecified DEPLOYMENT_TARGET
567 // Remove undesirable ancient cruft
568 CFDictionaryRef dict
= __CFTimeZoneCopyCompatibilityDictionary();
570 for (idx
= CFArrayGetCount(list
); idx
--; ) {
571 CFStringRef item
= (CFStringRef
)CFArrayGetValueAtIndex(list
, idx
);
572 if (CFDictionaryContainsKey(dict
, item
)) {
573 CFArrayRemoveValueAtIndex(list
, idx
);
576 __CFKnownTimeZoneList
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, list
);
579 tzs
= __CFKnownTimeZoneList
? (CFArrayRef
)CFRetain(__CFKnownTimeZoneList
) : NULL
;
580 __CFTimeZoneUnlockGlobal();
584 #if DEPLOYMENT_TARGET_MACOSX
585 /* The criteria here are sort of: coverage for the U.S. and Europe,
586 * large cities, abbreviation uniqueness, and perhaps a few others.
587 * But do not make the list too large with obscure information.
589 static const char *__CFTimeZoneAbbreviationDefaults
=
590 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
591 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
592 " <plist version=\"1.0\">"
594 " <key>ADT</key> <string>America/Halifax</string>"
595 " <key>AKDT</key> <string>America/Juneau</string>"
596 " <key>AKST</key> <string>America/Juneau</string>"
597 " <key>ART</key> <string>America/Argentina/Buenos_Aires</string>"
598 " <key>AST</key> <string>America/Halifax</string>"
599 " <key>BDT</key> <string>Asia/Dhaka</string>"
600 " <key>BRST</key> <string>America/Sao_Paulo</string>"
601 " <key>BRT</key> <string>America/Sao_Paulo</string>"
602 " <key>BST</key> <string>Europe/London</string>"
603 " <key>CAT</key> <string>Africa/Harare</string>"
604 " <key>CDT</key> <string>America/Chicago</string>"
605 " <key>CEST</key> <string>Europe/Paris</string>"
606 " <key>CET</key> <string>Europe/Paris</string>"
607 " <key>CLST</key> <string>America/Santiago</string>"
608 " <key>CLT</key> <string>America/Santiago</string>"
609 " <key>COT</key> <string>America/Bogota</string>"
610 " <key>CST</key> <string>America/Chicago</string>"
611 " <key>EAT</key> <string>Africa/Addis_Ababa</string>"
612 " <key>EDT</key> <string>America/New_York</string>"
613 " <key>EEST</key> <string>Europe/Istanbul</string>"
614 " <key>EET</key> <string>Europe/Istanbul</string>"
615 " <key>EST</key> <string>America/New_York</string>"
616 " <key>GMT</key> <string>GMT</string>"
617 " <key>GST</key> <string>Asia/Dubai</string>"
618 " <key>HKT</key> <string>Asia/Hong_Kong</string>"
619 " <key>HST</key> <string>Pacific/Honolulu</string>"
620 " <key>ICT</key> <string>Asia/Bangkok</string>"
621 " <key>IRST</key> <string>Asia/Tehran</string>"
622 " <key>IST</key> <string>Asia/Calcutta</string>"
623 " <key>JST</key> <string>Asia/Tokyo</string>"
624 " <key>KST</key> <string>Asia/Seoul</string>"
625 " <key>MDT</key> <string>America/Denver</string>"
626 " <key>MSD</key> <string>Europe/Moscow</string>"
627 " <key>MSK</key> <string>Europe/Moscow</string>"
628 " <key>MST</key> <string>America/Denver</string>"
629 " <key>NZDT</key> <string>Pacific/Auckland</string>"
630 " <key>NZST</key> <string>Pacific/Auckland</string>"
631 " <key>PDT</key> <string>America/Los_Angeles</string>"
632 " <key>PET</key> <string>America/Lima</string>"
633 " <key>PHT</key> <string>Asia/Manila</string>"
634 " <key>PKT</key> <string>Asia/Karachi</string>"
635 " <key>PST</key> <string>America/Los_Angeles</string>"
636 " <key>SGT</key> <string>Asia/Singapore</string>"
637 " <key>UTC</key> <string>UTC</string>"
638 " <key>WAT</key> <string>Africa/Lagos</string>"
639 " <key>WEST</key> <string>Europe/Lisbon</string>"
640 " <key>WET</key> <string>Europe/Lisbon</string>"
641 " <key>WIT</key> <string>Asia/Jakarta</string>"
645 static const char *__CFTimeZoneAbbreviationDefaults
=
646 /* Mappings to time zones in Windows Registry are best-guess */
647 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
648 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
649 " <plist version=\"1.0\">"
651 " <key>ADT</key> <string>Atlantic Standard Time</string>"
652 " <key>AKDT</key> <string>Alaskan Standard Time</string>"
653 " <key>AKST</key> <string>Alaskan Standard Time</string>"
654 " <key>ART</key> <string>SA Eastern Standard Time</string>"
655 " <key>AST</key> <string>Atlantic Standard Time</string>"
656 " <key>BDT</key> <string>Central Asia Standard Time</string>"
657 " <key>BRST</key> <string>SA Eastern Standard Time</string>"
658 " <key>BRT</key> <string>SA Eastern Standard Time</string>"
659 " <key>BST</key> <string>GMT Standard Time</string>"
660 " <key>CAT</key> <string>South Africa Standard Time</string>"
661 " <key>CDT</key> <string>Central Standard Time</string>"
662 " <key>CEST</key> <string>Central Europe Standard Time</string>"
663 " <key>CET</key> <string>Central Europe Standard Time</string>"
664 " <key>CLST</key> <string>SA Western Standard Time</string>"
665 " <key>CLT</key> <string>SA Western Standard Time</string>"
666 " <key>COT</key> <string>Central Standard Time</string>"
667 " <key>CST</key> <string>Central Standard Time</string>"
668 " <key>EAT</key> <string>E. Africa Standard Time</string>"
669 " <key>EDT</key> <string>Eastern Standard Time</string>"
670 " <key>EEST</key> <string>E. Europe Standard Time</string>"
671 " <key>EET</key> <string>E. Europe Standard Time</string>"
672 " <key>EST</key> <string>Eastern Standard Time</string>"
673 " <key>GMT</key> <string>Greenwich Standard Time</string>"
674 " <key>GST</key> <string>Arabian Standard Time</string>"
675 " <key>HKT</key> <string>China Standard Time</string>"
676 " <key>HST</key> <string>Hawaiian Standard Time</string>"
677 " <key>ICT</key> <string>SE Asia Standard Time</string>"
678 " <key>IRST</key> <string>Iran Standard Time</string>"
679 " <key>IST</key> <string>India Standard Time</string>"
680 " <key>JST</key> <string>Tokyo Standard Time</string>"
681 " <key>KST</key> <string>Korea Standard Time</string>"
682 " <key>MDT</key> <string>Mountain Standard Time</string>"
683 " <key>MSD</key> <string>E. Europe Standard Time</string>"
684 " <key>MSK</key> <string>E. Europe Standard Time</string>"
685 " <key>MST</key> <string>Mountain Standard Time</string>"
686 " <key>NZDT</key> <string>New Zealand Standard Time</string>"
687 " <key>NZST</key> <string>New Zealand Standard Time</string>"
688 " <key>PDT</key> <string>Pacific Standard Time</string>"
689 " <key>PET</key> <string>SA Pacific Standard Time</string>"
690 " <key>PHT</key> <string>Taipei Standard Time</string>"
691 " <key>PKT</key> <string>West Asia Standard Time</string>"
692 " <key>PST</key> <string>Pacific Standard Time</string>"
693 " <key>SGT</key> <string>Singapore Standard Time</string>"
694 " <key>UTC</key> <string>Greenwich Standard Time</string>"
695 " <key>WAT</key> <string>W. Central Africa Standard Time</string>"
696 " <key>WEST</key> <string>W. Europe Standard Time</string>"
697 " <key>WET</key> <string>W. Europe Standard Time</string>"
698 " <key>WIT</key> <string>SE Asia Standard Time</string>"
702 #error Unknown or unspecified DEPLOYMENT_TARGET
705 CFDictionaryRef
CFTimeZoneCopyAbbreviationDictionary(void) {
706 CFDictionaryRef dict
;
707 __CFTimeZoneLockAbbreviations();
708 if (NULL
== __CFTimeZoneAbbreviationDict
) {
709 CFDataRef data
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)__CFTimeZoneAbbreviationDefaults
, strlen(__CFTimeZoneAbbreviationDefaults
));
710 __CFTimeZoneAbbreviationDict
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, data
, kCFPropertyListImmutable
, NULL
);
713 if (NULL
== __CFTimeZoneAbbreviationDict
) {
714 __CFTimeZoneAbbreviationDict
= CFDictionaryCreate(kCFAllocatorSystemDefault
, NULL
, NULL
, 0, NULL
, NULL
);
716 dict
= __CFTimeZoneAbbreviationDict
? (CFDictionaryRef
)CFRetain(__CFTimeZoneAbbreviationDict
) : NULL
;
717 __CFTimeZoneUnlockAbbreviations();
721 void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict
) {
722 __CFGenericValidateType(dict
, CFDictionaryGetTypeID());
723 __CFTimeZoneLockGlobal();
724 if (dict
!= __CFTimeZoneAbbreviationDict
) {
725 if (dict
) CFRetain(dict
);
726 if (__CFTimeZoneAbbreviationDict
) {
728 count
= CFDictionaryGetCount(__CFTimeZoneAbbreviationDict
);
729 CFTypeRef
*keys
= (CFTypeRef
*)malloc(sizeof(CFTypeRef
*) * count
);
730 for (idx
= 0; idx
< count
; idx
++) {
731 CFDictionaryRemoveValue(__CFTimeZoneCache
, (CFStringRef
)keys
[idx
]);
734 CFRelease(__CFTimeZoneAbbreviationDict
);
736 __CFTimeZoneAbbreviationDict
= dict
;
738 __CFTimeZoneUnlockGlobal();
741 CFTimeZoneRef
CFTimeZoneCreate(CFAllocatorRef allocator
, CFStringRef name
, CFDataRef data
) {
742 // assert: (NULL != name && NULL != data);
743 CFTimeZoneRef memory
;
745 CFTZPeriod
*tzp
= NULL
;
746 CFIndex idx
, cnt
= 0;
748 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
749 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
750 __CFGenericValidateType(name
, CFStringGetTypeID());
751 __CFGenericValidateType(data
, CFDataGetTypeID());
752 __CFTimeZoneLockGlobal();
753 if (NULL
!= __CFTimeZoneCache
&& CFDictionaryGetValueIfPresent(__CFTimeZoneCache
, name
, (const void **)&memory
)) {
754 __CFTimeZoneUnlockGlobal();
755 return (CFTimeZoneRef
)CFRetain(memory
);
757 if (!__CFParseTimeZoneData(allocator
, data
, &tzp
, &cnt
)) {
758 __CFTimeZoneUnlockGlobal();
761 size
= sizeof(struct __CFTimeZone
) - sizeof(CFRuntimeBase
);
762 memory
= (CFTimeZoneRef
)_CFRuntimeCreateInstance(allocator
, CFTimeZoneGetTypeID(), size
, NULL
);
763 if (NULL
== memory
) {
764 __CFTimeZoneUnlockGlobal();
765 for (idx
= 0; idx
< cnt
; idx
++) {
766 if (NULL
!= tzp
[idx
].abbrev
) CFRelease(tzp
[idx
].abbrev
);
768 if (NULL
!= tzp
) CFAllocatorDeallocate(allocator
, tzp
);
771 ((struct __CFTimeZone
*)memory
)->_name
= (CFStringRef
)CFStringCreateCopy(allocator
, name
);
772 ((struct __CFTimeZone
*)memory
)->_data
= CFDataCreateCopy(allocator
, data
);
773 ((struct __CFTimeZone
*)memory
)->_periods
= tzp
;
774 ((struct __CFTimeZone
*)memory
)->_periodCnt
= cnt
;
775 if (NULL
== __CFTimeZoneCache
) {
776 __CFTimeZoneCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
778 CFDictionaryAddValue(__CFTimeZoneCache
, ((struct __CFTimeZone
*)memory
)->_name
, memory
);
779 __CFTimeZoneUnlockGlobal();
783 #if DEPLOYMENT_TARGET_MACOSX
784 static CFTimeZoneRef
__CFTimeZoneCreateFixed(CFAllocatorRef allocator
, int32_t seconds
, CFStringRef name
, int isDST
) {
785 CFTimeZoneRef result
;
787 int32_t nameLen
= CFStringGetLength(name
);
788 unsigned char dataBytes
[52 + nameLen
+ 1];
789 memset(dataBytes
, 0, sizeof(dataBytes
));
791 // Put in correct magic bytes for timezone structures
797 __CFEntzcode(1, dataBytes
+ 20);
798 __CFEntzcode(1, dataBytes
+ 24);
799 __CFEntzcode(1, dataBytes
+ 36);
800 __CFEntzcode(nameLen
+ 1, dataBytes
+ 40);
801 __CFEntzcode(seconds
, dataBytes
+ 44);
802 dataBytes
[48] = isDST
? 1 : 0;
803 CFStringGetCString(name
, (char *)dataBytes
+ 50, nameLen
+ 1, kCFStringEncodingASCII
);
804 data
= CFDataCreate(allocator
, dataBytes
, 52 + nameLen
+ 1);
805 result
= CFTimeZoneCreate(allocator
, name
, data
);
810 static CFTimeZoneRef
__CFTimeZoneCreateFixed(CFAllocatorRef allocator
, int32_t seconds
, CFStringRef name
, int isDST
) {
811 /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure
812 * to find current timezone
813 * (Aleksey Dukhnyakov)
815 CFTimeZoneRef result
;
816 TIME_ZONE_INFORMATION tzi
;
818 CFIndex length
= CFStringGetLength(name
);
820 memset(&tzi
,0,sizeof(tzi
));
821 tzi
.Bias
=(long)(-seconds
/60);
822 CFStringGetCharacters(name
, CFRangeMake(0, length
< 31 ? length
: 31 ), (UniChar
*)tzi
.StandardName
);
823 data
= CFDataCreate(allocator
,(UInt8
*)&tzi
, sizeof(tzi
));
824 result
= CFTimeZoneCreate(allocator
, name
, data
);
829 #error Unknown or unspecified DEPLOYMENT_TARGET
832 // rounds offset to nearest minute
833 CFTimeZoneRef
CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator
, CFTimeInterval ti
) {
834 CFTimeZoneRef result
;
836 int32_t seconds
, minute
, hour
;
837 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
838 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
839 if (ti
< -18.0 * 3600 || 18.0 * 3600 < ti
) return NULL
;
840 ti
= (ti
< 0.0) ? ceil((ti
/ 60.0) - 0.5) * 60.0 : floor((ti
/ 60.0) + 0.5) * 60.0;
841 seconds
= (int32_t)ti
;
842 hour
= (ti
< 0) ? (-seconds
/ 3600) : (seconds
/ 3600);
843 seconds
-= ((ti
< 0) ? -hour
: hour
) * 3600;
844 minute
= (ti
< 0) ? (-seconds
/ 60) : (seconds
/ 60);
845 if (fabs(ti
) < 1.0) {
846 name
= (CFStringRef
)CFRetain(CFSTR("GMT"));
848 name
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("GMT%c%02d%02d"), (ti
< 0.0 ? '-' : '+'), hour
, minute
);
850 result
= __CFTimeZoneCreateFixed(allocator
, (int32_t)ti
, name
, 0);
855 CFTimeZoneRef
CFTimeZoneCreateWithName(CFAllocatorRef allocator
, CFStringRef name
, Boolean tryAbbrev
) {
856 CFTimeZoneRef result
= NULL
;
857 CFStringRef tzName
= NULL
;
858 CFDataRef data
= NULL
;
860 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
861 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
862 __CFGenericValidateType(name
, CFStringGetTypeID());
863 if (CFEqual(CFSTR(""), name
)) {
864 // empty string is not a time zone name, just abort now,
865 // following stuff will fail anyway
868 __CFTimeZoneLockGlobal();
869 if (NULL
!= __CFTimeZoneCache
&& CFDictionaryGetValueIfPresent(__CFTimeZoneCache
, name
, (const void **)&result
)) {
870 __CFTimeZoneUnlockGlobal();
871 return (CFTimeZoneRef
)CFRetain(result
);
873 __CFTimeZoneUnlockGlobal();
874 #if DEPLOYMENT_TARGET_MACOSX
875 CFURLRef baseURL
, tempURL
;
879 baseURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, CFSTR(TZZONEINFO
), kCFURLPOSIXPathStyle
, true);
881 CFDictionaryRef abbrevs
= CFTimeZoneCopyAbbreviationDictionary();
882 tzName
= CFDictionaryGetValue(abbrevs
, name
);
883 if (NULL
!= tzName
) {
884 tempURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault
, baseURL
, tzName
, false);
885 if (NULL
!= tempURL
) {
886 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault
, tempURL
, &bytes
, &length
, 0)) {
887 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, bytes
, length
, kCFAllocatorSystemDefault
);
895 CFDictionaryRef dict
= __CFTimeZoneCopyCompatibilityDictionary();
896 CFStringRef mapping
= CFDictionaryGetValue(dict
, name
);
899 } else if (CFStringHasPrefix(name
, CFSTR(TZZONEINFO
))) {
900 CFMutableStringRef unprefixed
= CFStringCreateMutableCopy(kCFAllocatorSystemDefault
, CFStringGetLength(name
), name
);
901 CFStringDelete(unprefixed
, CFRangeMake(0, sizeof(TZZONEINFO
)));
902 mapping
= CFDictionaryGetValue(dict
, unprefixed
);
906 CFRelease(unprefixed
);
909 if (CFEqual(CFSTR(""), name
)) {
915 tempURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault
, baseURL
, tzName
, false);
916 if (NULL
!= tempURL
) {
917 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault
, tempURL
, &bytes
, &length
, 0)) {
918 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, bytes
, length
, kCFAllocatorSystemDefault
);
925 result
= CFTimeZoneCreate(allocator
, tzName
, data
);
926 if (name
!= tzName
) {
927 CFStringRef nameCopy
= (CFStringRef
)CFStringCreateCopy(allocator
, name
);
928 __CFTimeZoneLockGlobal();
929 CFDictionaryAddValue(__CFTimeZoneCache
, nameCopy
, result
);
930 __CFTimeZoneUnlockGlobal();
938 /* Reading GMT offset and daylight flag from the registry
940 * (Aleksey Dukhnyakov)
943 CFStringRef safeName
= name
;
948 SYSTEMTIME StandardDate
;
949 SYSTEMTIME DaylightDate
;
951 TIME_ZONE_INFORMATION tzi_system
;
954 DWORD dwType
, dwSize
=sizeof(tzi
),
955 dwSize_name1
=sizeof(tzi_system
.StandardName
),
956 dwSize_name2
=sizeof(tzi_system
.DaylightName
);
959 CFDictionaryRef abbrevs
= CFTimeZoneCopyAbbreviationDictionary();
960 tzName
= (CFStringRef
)CFDictionaryGetValue(abbrevs
, name
);
961 if (NULL
== tzName
) {
969 /* Open regestry and move down to the TimeZone information
971 if (RegOpenKey(HKEY_LOCAL_MACHINE
,_T(TZZONEINFO
),&hkResult
) !=
975 /* Move down to specific TimeZone name
978 UniChar
*uniTimeZone
= (UniChar
*)CFStringGetCharactersPtr(name
);
979 if (uniTimeZone
== NULL
) {
980 // We need to extract the bytes out of the CFStringRef and create our own
981 // UNICODE string to pass to the Win32 API - RegOpenKey.
982 UInt8 uniBuff
[MAX_PATH
+2]; // adding +2 to handle Unicode-null termination /0/0.
983 CFIndex usedBuff
= 0;
984 CFIndex numChars
= CFStringGetBytes(name
, CFRangeMake(0, CFStringGetLength(name
)), kCFStringEncodingUnicode
, 0, FALSE
, uniBuff
, MAX_PATH
, &usedBuff
);
988 // NULL-terminate the newly created Unicode string.
989 uniBuff
[usedBuff
] = '\0';
990 uniBuff
[usedBuff
+1] = '\0';
993 if (RegOpenKey(hkResult
, (LPCWSTR
)uniBuff
,&hkResult
) != ERROR_SUCCESS
) {
997 if (RegOpenKey(hkResult
, (LPCWSTR
)uniTimeZone
,&hkResult
) != ERROR_SUCCESS
) {
1002 if (RegOpenKey(hkResult
,CFStringGetCStringPtr(name
, CFStringGetSystemEncoding()),&hkResult
) != ERROR_SUCCESS
) {
1007 /* TimeZone information(offsets, daylight flag, ...) assign to tzi structure
1009 if ( RegQueryValueEx(hkResult
,_T("TZI"),NULL
,&dwType
,(LPBYTE
)&tzi
,&dwSize
) != ERROR_SUCCESS
&&
1010 RegQueryValueEx(hkResult
,_T("Std"),NULL
,&dwType
,(LPBYTE
)&tzi_system
.StandardName
,&dwSize_name1
) != ERROR_SUCCESS
&&
1011 RegQueryValueEx(hkResult
,_T("Dlt"),NULL
,&dwType
,(LPBYTE
)&tzi_system
.DaylightName
,&dwSize_name2
) != ERROR_SUCCESS
)
1016 tzi_system
.Bias
=tzi
.Bias
;
1017 tzi_system
.StandardBias
=tzi
.StandardBias
;
1018 tzi_system
.DaylightBias
=tzi
.DaylightBias
;
1019 tzi_system
.StandardDate
=tzi
.StandardDate
;
1020 tzi_system
.DaylightDate
=tzi
.DaylightDate
;
1022 /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure
1023 * to find current timezone
1024 * (Aleksey Dukhnyakov)
1026 data
= CFDataCreate(allocator
,(UInt8
*)&tzi_system
, sizeof(tzi_system
));
1028 RegCloseKey(hkResult
);
1029 result
= CFTimeZoneCreate(allocator
, name
, data
);
1032 result
->_periods
->abbrev
= (CFStringRef
)CFStringCreateCopy(allocator
,safeName
);
1041 #error Unknown or unspecified DEPLOYMENT_TARGET
1044 CFStringRef
CFTimeZoneGetName(CFTimeZoneRef tz
) {
1045 CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFStringRef
, tz
, "name");
1046 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1050 CFDataRef
CFTimeZoneGetData(CFTimeZoneRef tz
) {
1051 CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFDataRef
, tz
, "data");
1052 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1056 CFTimeInterval
CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1057 #if DEPLOYMENT_TARGET_MACOSX
1059 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval
, tz
, "_secondsFromGMTForAbsoluteTime:", at
);
1060 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1061 idx
= __CFBSearchTZPeriods(tz
, at
);
1062 return __CFTZPeriodGMTOffset(&(tz
->_periods
[idx
]));
1066 CFStringRef
CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1069 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFStringRef
, tz
, "_abbreviationForAbsoluteTime:", at
);
1070 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1071 #if DEPLOYMENT_TARGET_MACOSX
1072 idx
= __CFBSearchTZPeriods(tz
, at
);
1074 result
= __CFTZPeriodAbbreviation(&(tz
->_periods
[idx
]));
1075 return result
? (CFStringRef
)CFRetain(result
) : NULL
;
1078 Boolean
CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1079 #if DEPLOYMENT_TARGET_MACOSX
1081 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), Boolean
, tz
, "_isDaylightSavingTimeForAbsoluteTime:", at
);
1082 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1083 idx
= __CFBSearchTZPeriods(tz
, at
);
1084 return __CFTZPeriodIsDST(&(tz
->_periods
[idx
]));
1088 CFTimeInterval
CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1089 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval
, tz
, "_daylightSavingTimeOffsetForAbsoluteTime:", at
);
1090 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1091 CFIndex idx
= __CFBSearchTZPeriods(tz
, at
);
1092 if (__CFTZPeriodIsDST(&(tz
->_periods
[idx
]))) {
1093 CFTimeInterval offset
= __CFTZPeriodGMTOffset(&(tz
->_periods
[idx
]));
1094 if (idx
+ 1 < tz
->_periodCnt
) {
1095 return offset
- __CFTZPeriodGMTOffset(&(tz
->_periods
[idx
+ 1]));
1096 } else if (0 < idx
) {
1097 return offset
- __CFTZPeriodGMTOffset(&(tz
->_periods
[idx
- 1]));
1103 CFAbsoluteTime
CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz
, CFAbsoluteTime at
) {
1104 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval
, tz
, "_nextDaylightSavingTimeTransitionAfterAbsoluteTime:", at
);
1105 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1106 CFIndex idx
= __CFBSearchTZPeriods(tz
, at
);
1107 if (tz
->_periodCnt
<= idx
+ 1) {
1110 return (CFAbsoluteTime
)__CFTZPeriodStartSeconds(&(tz
->_periods
[idx
+ 1]));
1114 kCFTimeZoneNameStyleGeneric
= 4,
1115 kCFTimeZoneNameStyleShortGeneric
= 5
1118 extern UCalendar
*__CFCalendarCreateUCalendar(CFStringRef calendarID
, CFStringRef localeID
, CFTimeZoneRef tz
);
1120 #define BUFFER_SIZE 768
1122 CFStringRef
CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz
, CFTimeZoneNameStyle style
, CFLocaleRef locale
) {
1123 CF_OBJC_FUNCDISPATCH2(CFTimeZoneGetTypeID(), CFStringRef
, tz
, "localizedName:locale:", style
, locale
);
1124 __CFGenericValidateType(tz
, CFTimeZoneGetTypeID());
1125 __CFGenericValidateType(locale
, CFLocaleGetTypeID());
1128 CFStringRef localeID
= CFLocaleGetIdentifier(locale
);
1129 UCalendar
*cal
= __CFCalendarCreateUCalendar(NULL
, localeID
, tz
);
1134 char buffer
[BUFFER_SIZE
];
1135 const char *cstr
= CFStringGetCStringPtr(localeID
, kCFStringEncodingASCII
);
1137 if (CFStringGetCString(localeID
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
1144 UChar ubuffer
[BUFFER_SIZE
];
1145 UErrorCode status
= U_ZERO_ERROR
;
1146 int32_t cnt
= ucal_getTimeZoneDisplayName(cal
, (UCalendarDisplayNameType
)style
, cstr
, ubuffer
, BUFFER_SIZE
, &status
);
1148 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1149 return CFStringCreateWithCharacters(CFGetAllocator(tz
), (const UniChar
*)ubuffer
, cnt
);
1154 static CFDictionaryRef
__CFTimeZoneCopyCompatibilityDictionary(void) {
1155 CFDictionaryRef dict
;
1156 __CFTimeZoneLockCompatibilityMapping();
1157 if (NULL
== __CFTimeZoneCompatibilityMappingDict
) {
1158 __CFTimeZoneCompatibilityMappingDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 112, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1160 // Empty string means delete/ignore these
1162 dict
= __CFTimeZoneCompatibilityMappingDict
? (CFDictionaryRef
)CFRetain(__CFTimeZoneCompatibilityMappingDict
) : NULL
;
1163 __CFTimeZoneUnlockCompatibilityMapping();