/ NSTimeZone.m
NSTimeZone.m
1 // 2 // NSTimeZone.m 3 // CoreFoundation 4 // 5 // Copyright (c) 2014 Apportable. All rights reserved. 6 // 7 8 #import "NSTimeZoneInternal.h" 9 #import "NSObjectInternal.h" 10 #import <Foundation/NSCache.h> 11 #import "CFInternal.h" 12 13 @implementation NSTimeZone 14 15 + (id)allocWithZone:(NSZone *)zone 16 { 17 if (self == [NSTimeZone class]) 18 { 19 return [__NSPlaceholderTimeZone immutablePlaceholder]; 20 } 21 else 22 { 23 return [super allocWithZone:zone]; 24 } 25 } 26 27 - (NSString *)name 28 { 29 NSRequestConcreteImplementation(); 30 return nil; 31 } 32 33 - (NSData *)data 34 { 35 NSRequestConcreteImplementation(); 36 return nil; 37 } 38 39 - (NSInteger)secondsFromGMTForDate:(NSDate *)aDate 40 { 41 NSRequestConcreteImplementation(); 42 return 0; 43 } 44 45 - (NSString *)abbreviationForDate:(NSDate *)aDate 46 { 47 NSRequestConcreteImplementation(); 48 return nil; 49 } 50 51 - (BOOL)isDaylightSavingTimeForDate:(NSDate *)aDate 52 { 53 NSRequestConcreteImplementation(); 54 return NO; 55 } 56 57 - (NSTimeInterval)daylightSavingTimeOffsetForDate:(NSDate *)aDate 58 { 59 NSRequestConcreteImplementation(); 60 return 0.0; 61 } 62 63 - (NSDate *)nextDaylightSavingTimeTransitionAfterDate:(NSDate *)aDate 64 { 65 NSRequestConcreteImplementation(); 66 return nil; 67 } 68 69 - (id)copyWithZone:(NSZone *)zone 70 { 71 NSRequestConcreteImplementation(); 72 return nil; 73 } 74 75 + (BOOL)supportsSecureCoding 76 { 77 return NO; 78 } 79 80 - (CFTypeID)_cfTypeID 81 { 82 return CFTimeZoneGetTypeID(); 83 } 84 85 - (BOOL)isNSTimeZone__ 86 { 87 return YES; 88 } 89 90 @end 91 92 @implementation NSTimeZone (NSExtendedTimeZone) 93 94 + (NSTimeZone *)systemTimeZone 95 { 96 return [(NSTimeZone *)CFTimeZoneCopySystem() autorelease]; 97 } 98 99 + (void)resetSystemTimeZone 100 { 101 CFTimeZoneResetSystem(); 102 } 103 104 + (NSTimeZone *)defaultTimeZone 105 { 106 return [(NSTimeZone *)CFTimeZoneCopyDefault() autorelease]; 107 } 108 109 + (void)setDefaultTimeZone:(NSTimeZone *)aTimeZone 110 { 111 CFTimeZoneSetDefault((CFTimeZoneRef)aTimeZone); 112 } 113 114 + (NSTimeZone *)localTimeZone 115 { 116 static NSTimeZone *localTZ = nil; 117 static dispatch_once_t once = 0L; 118 dispatch_once(&once, ^{ 119 CFStringRef zoneName = CFStringCreateWithCString(kCFAllocatorDefault, getenv("TZ"), kCFStringEncodingUTF8); 120 localTZ = (NSTimeZone *)CFTimeZoneCreateWithName(NULL, zoneName, false); 121 [localTZ retain]; 122 CFRelease(zoneName); 123 }); 124 return localTZ; 125 } 126 127 + (NSArray *)knownTimeZoneNames 128 { 129 return [(NSArray *)CFTimeZoneCopyKnownNames() autorelease]; 130 } 131 132 + (NSDictionary *)abbreviationDictionary 133 { 134 return [(NSDictionary *)CFTimeZoneCopyAbbreviationDictionary() autorelease]; 135 } 136 137 + (void)setAbbreviationDictionary:(NSDictionary *)dict 138 { 139 CFTimeZoneSetAbbreviationDictionary((CFDictionaryRef)dict); 140 } 141 142 - (NSInteger)secondsFromGMT 143 { 144 return [self secondsFromGMTForDate:[NSDate date]]; 145 } 146 147 - (NSString *)abbreviation 148 { 149 NSRequestConcreteImplementation(); 150 return nil; 151 } 152 153 - (BOOL)isDaylightSavingTime 154 { 155 return [self isDaylightSavingTimeForDate:[NSDate date]]; 156 } 157 158 - (NSTimeInterval)daylightSavingTimeOffset 159 { 160 return [self daylightSavingTimeOffsetForDate:[NSDate date]]; 161 } 162 163 - (NSDate *)nextDaylightSavingTimeTransition 164 { 165 return [self nextDaylightSavingTimeTransitionAfterDate:[NSDate date]]; 166 } 167 168 - (BOOL)isEqualToTimeZone:(NSTimeZone *)aTimeZone 169 { 170 return [[self name] isEqualToString:[aTimeZone name]] && [[self data] isEqualToData:[aTimeZone data]]; 171 } 172 173 - (NSString *)localizedName:(NSTimeZoneNameStyle)style locale:(NSLocale *)locale 174 { 175 NSRequestConcreteImplementation(); 176 return nil; 177 } 178 179 180 @end 181 182 @implementation NSTimeZone (NSTimeZoneCreation) 183 184 + (id)timeZoneWithName:(NSString *)tzName 185 { 186 return [[[NSTimeZone alloc] initWithName:tzName] autorelease]; 187 } 188 189 + (id)timeZoneWithName:(NSString *)tzName data:(NSData *)aData 190 { 191 return [[[self alloc] initWithName:tzName data:aData] autorelease]; 192 } 193 194 + (id)timeZoneForSecondsFromGMT:(NSInteger)seconds 195 { 196 return [(NSTimeZone *)CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, seconds) autorelease]; 197 } 198 199 + (id)timeZoneWithAbbreviation:(NSString *)abbreviation 200 { 201 CFStringRef name = CFDictionaryGetValue((CFDictionaryRef)[NSTimeZone abbreviationDictionary], abbreviation); 202 if (name != nil) 203 { 204 return [[[self alloc] initWithName:(NSString *)name] autorelease]; 205 } 206 return nil; 207 } 208 209 210 - (id)initWithName:(NSString *)tzName 211 { 212 NSRequestConcreteImplementation(); 213 [self release]; 214 return nil; 215 } 216 217 - (id)initWithName:(NSString *)tzName data:(NSData *)aData 218 { 219 NSRequestConcreteImplementation(); 220 [self release]; 221 return nil; 222 } 223 224 @end 225 226 @implementation __NSPlaceholderTimeZone 227 228 static NSCache *tzCache = nil; 229 230 + (id)immutablePlaceholder 231 { 232 static dispatch_once_t once = 0L; 233 static __NSPlaceholderTimeZone *placeholder = nil; 234 dispatch_once(&once, ^{ 235 placeholder = [__NSPlaceholderTimeZone alloc]; 236 }); 237 return placeholder; 238 } 239 240 + (void)initialize 241 { 242 static dispatch_once_t once = 0L; 243 dispatch_once(&once, ^{ 244 tzCache = [[NSCache alloc] init]; 245 }); 246 } 247 248 - (NSDate *)nextDaylightSavingTimeTransitionAfterDate:(NSDate *)aDate 249 { 250 NSRequestConcreteImplementation(); 251 return nil; 252 } 253 254 - (NSTimeInterval)daylightSavingTimeOffsetForDate:(NSDate *)aDate 255 { 256 NSRequestConcreteImplementation(); 257 return 0.0; 258 } 259 260 - (BOOL)isDaylightSavingTimeForDate:(NSDate *)aDate 261 { 262 NSRequestConcreteImplementation(); 263 return NO; 264 } 265 266 - (NSString *)abbreviationForDate:(NSDate *)aDate 267 { 268 NSRequestConcreteImplementation(); 269 return nil; 270 } 271 272 - (NSInteger)secondsFromGMTForDate:(NSDate *)aDate 273 { 274 NSRequestConcreteImplementation(); 275 return 0; 276 } 277 278 - (NSData *)data 279 { 280 NSRequestConcreteImplementation(); 281 return nil; 282 } 283 284 - (NSString *)name 285 { 286 NSRequestConcreteImplementation(); 287 return nil; 288 } 289 290 SINGLETON_RR() 291 292 - (id)init 293 { 294 return nil; 295 } 296 297 static NSTimeZone *NSTimeZoneCacheFind(NSString *name) 298 { 299 return [tzCache objectForKey:name]; 300 } 301 302 static void NSTimeZoneCacheAdd(NSString *name, NSTimeZone *tz) 303 { 304 [tzCache setObject:tz forKey:name cost:[[tz data] length]]; 305 } 306 307 - (id)initWithName:(NSString *)name 308 { 309 return (id)CFTimeZoneCreateWithName(kCFAllocatorDefault, (CFStringRef)name, YES); 310 } 311 312 - (id)initWithName:(NSString *)name data:(NSData *)data 313 { 314 return [self __initWithName:name data:data cache:NO]; 315 } 316 317 - (id)__initWithName:(NSString *)name data:(NSData *)data cache:(BOOL)shouldCache 318 { 319 NSTimeZone *tz = (NSTimeZone *)CFTimeZoneCreate(kCFAllocatorDefault, (CFStringRef)name, (CFDataRef)data); 320 321 if (tz != NULL && shouldCache) 322 { 323 NSTimeZoneCacheAdd(name, tz); 324 } 325 326 return (id)tz; 327 } 328 329 @end 330 331 @implementation __NSTimeZone 332 333 - (NSString *)localizedName:(NSTimeZoneNameStyle)style locale:(NSLocale *)locale 334 { 335 return [(NSString *)CFTimeZoneCopyLocalizedName((CFTimeZoneRef)self, (CFTimeZoneNameStyle)style, (CFLocaleRef)locale) autorelease]; 336 } 337 338 - (NSDate *)nextDaylightSavingTimeTransitionAfterDate:(NSDate *)aDate 339 { 340 CFAbsoluteTime time = CFTimeZoneGetNextDaylightSavingTimeTransition((CFTimeZoneRef)self, [aDate timeIntervalSinceReferenceDate]); 341 return (time == 0) ? nil : [NSDate dateWithTimeIntervalSinceReferenceDate:time]; 342 } 343 344 - (NSTimeInterval)daylightSavingTimeOffsetForDate:(NSDate *)aDate 345 { 346 return CFTimeZoneGetDaylightSavingTimeOffset((CFTimeZoneRef)self, [aDate timeIntervalSinceReferenceDate]); 347 } 348 349 - (BOOL)isDaylightSavingTimeForDate:(NSDate *)aDate 350 { 351 return CFTimeZoneIsDaylightSavingTime((CFTimeZoneRef)self, [aDate timeIntervalSinceReferenceDate]); 352 } 353 354 - (NSString *)abbreviationForDate:(NSDate *)aDate 355 { 356 //This implementation is more correct than calling CFTimeZoneCopyAbbreviation from this point. 357 //TODO - account for daylight savings by using ICU 358 const void *keys[48]; 359 const void *values[48]; 360 CFDictionaryGetKeysAndValues((CFDictionaryRef)[NSTimeZone abbreviationDictionary], keys, values); 361 362 for (int i = 0; i < 48; i++) 363 { 364 if ([((NSString*)values[i]) isEqualToString:[self name]]) 365 { 366 return keys[i]; 367 } 368 } 369 370 return nil; 371 372 //This date is not the date that is sourced for the timezone, but used for determining the current daylight savings status 373 //return [(NSString *)CFTimeZoneCopyAbbreviation((CFTimeZoneRef)self, [aDate timeIntervalSinceReferenceDate]) autorelease]; 374 } 375 376 - (NSString *)description 377 { 378 CFStringRef description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ (%@) %d"), [self name], [self abbreviation], [self secondsFromGMT]); 379 return [(NSString *)description autorelease]; 380 } 381 382 - (NSString *)abbreviation 383 { 384 return [self abbreviationForDate:[NSDate date]]; 385 } 386 387 - (NSInteger)secondsFromGMTForDate:(NSDate *)aDate 388 { 389 return CFTimeZoneGetSecondsFromGMT((CFTimeZoneRef)self, [aDate timeIntervalSinceReferenceDate]); 390 } 391 392 - (NSData *)data 393 { 394 return (NSData *)CFTimeZoneGetData((CFTimeZoneRef)self); 395 } 396 397 - (NSString *)name 398 { 399 return (NSString *)CFTimeZoneGetName((CFTimeZoneRef)self); 400 } 401 402 - (NSUInteger)retainCount 403 { 404 return CFGetRetainCount((CFTypeRef)self); 405 } 406 407 - (BOOL)_isDeallocating 408 { 409 return _CFIsDeallocating((CFTypeRef)self); 410 } 411 412 - (BOOL)_tryRetain 413 { 414 return _CFTryRetain((CFTypeRef)self) != NULL; 415 } 416 417 - (oneway void)release 418 { 419 CFRelease((CFTypeRef)self); 420 } 421 422 - (id)retain 423 { 424 return (id)CFRetain((CFTypeRef)self); 425 } 426 427 - (NSUInteger)hash 428 { 429 return CFHash((CFTypeRef)self); 430 } 431 432 - (BOOL)isEqual:(id)obj 433 { 434 if (obj == nil) 435 { 436 return NO; 437 } 438 return CFEqual((CFTypeRef)self, (CFTypeRef)obj); 439 } 440 441 @end