/ 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