/ NSDate.m
NSDate.m
  1  //
  2  //  NSDate.m
  3  //  CoreFoundation
  4  //
  5  //  Copyright (c) 2014 Apportable. All rights reserved.
  6  //
  7  
  8  
  9  #import <Foundation/NSDate.h>
 10  #import "NSObjectInternal.h"
 11  #import "ForFoundationOnly.h"
 12  #import <sys/time.h>
 13  
 14  CF_PRIVATE
 15  @interface __NSPlaceholderDate : NSDate
 16  + (id)immutablePlaceholder;
 17  @end
 18  
 19  CF_PRIVATE
 20  @interface __NSDate : NSDate {
 21      NSTimeInterval _time;
 22  }
 23  @end
 24  
 25  #define NSTimeInterval1970 978307200.0
 26  #define NSTimeIntervalDistantFuture 63113904000.0
 27  #define NSTimeIntervalDistantPast (-63114076800.0)
 28  
 29  
 30  @implementation NSDate
 31  
 32  + (id)allocWithZone:(NSZone *)zone
 33  {
 34      if (self == [NSDate class])
 35      {
 36          return [__NSPlaceholderDate immutablePlaceholder];
 37      }
 38      else
 39      {
 40          return [super allocWithZone:zone];
 41      }
 42  }
 43  
 44  - (NSTimeInterval)timeIntervalSinceReferenceDate
 45  {
 46      NSRequestConcreteImplementation();
 47      return 0.0;
 48  }
 49  
 50  - (CFTypeID)_cfTypeID
 51  {
 52      return CFDateGetTypeID();
 53  }
 54  
 55  + (BOOL)supportsSecureCoding
 56  {
 57      return NO;
 58  }
 59  
 60  - (id)copyWithZone:(NSZone *)zone
 61  {
 62      return [self retain];
 63  }
 64  
 65  - (BOOL)isNSDate__
 66  {
 67      return YES;
 68  }
 69  
 70  @end
 71  
 72  @implementation NSDate (NSExtendedDate)
 73  
 74  + (NSTimeInterval)timeIntervalSinceReferenceDate
 75  {
 76      return CFAbsoluteTimeGetCurrent();
 77  }
 78  
 79  - (NSTimeInterval)timeIntervalSinceDate:(NSDate *)other
 80  {
 81      return [self timeIntervalSinceReferenceDate] - [other timeIntervalSinceReferenceDate];
 82  }
 83  
 84  - (NSTimeInterval)timeIntervalSinceNow
 85  {
 86      return [self timeIntervalSinceReferenceDate] - CFAbsoluteTimeGetCurrent();
 87  }
 88  
 89  - (NSTimeInterval)timeIntervalSince1970
 90  {
 91      return [self timeIntervalSinceReferenceDate] + NSTimeInterval1970;
 92  }
 93  
 94  - (id)addTimeInterval:(NSTimeInterval)seconds
 95  {
 96      return [self dateByAddingTimeInterval:seconds];
 97  }
 98  
 99  - (id)dateByAddingTimeInterval:(NSTimeInterval)ti
100  {
101      return [[[NSDate alloc] initWithTimeIntervalSinceReferenceDate:[self timeIntervalSinceReferenceDate] + ti] autorelease];
102  }
103  
104  - (NSDate *)earlierDate:(NSDate *)other
105  {
106      if (other == nil)
107      {
108          return self;
109      }
110      
111      if ([other timeIntervalSinceReferenceDate] < [self timeIntervalSinceReferenceDate])
112      {
113          return other;
114      }
115      else
116      {
117          return self;
118      }
119  }
120  
121  - (NSDate *)laterDate:(NSDate *)other
122  {
123      if (other == nil)
124      {
125          return self;
126      }
127      
128      if ([other timeIntervalSinceReferenceDate] > [self timeIntervalSinceReferenceDate])
129      {
130          return other;
131      }
132      else
133      {
134          return self;
135      }
136  }
137  
138  - (NSComparisonResult)compare:(NSDate *)other
139  {
140      NSTimeInterval t1 = [self timeIntervalSinceReferenceDate];
141      NSTimeInterval t2 = [other timeIntervalSinceReferenceDate];
142      if (t1 < t2)
143      {
144          return NSOrderedAscending;
145      }
146      else if (t1 > t2)
147      {
148          return NSOrderedDescending;
149      }
150      else
151      {
152          return NSOrderedSame;
153      }
154  }
155  
156  - (NSUInteger)hash
157  {
158      return (NSUInteger)[self timeIntervalSinceReferenceDate];
159  }
160  
161  - (BOOL)isEqual:(id)other
162  {
163      if (![other isNSDate__])
164      {
165          return NO;
166      }
167      return [self isEqualToDate:other];
168  }
169  
170  - (BOOL)isEqualToDate:(NSDate *)other
171  {
172      return [other timeIntervalSinceReferenceDate] == [self timeIntervalSinceReferenceDate];
173  }
174  
175  - (NSString *)description
176  {
177      return [self descriptionWithLocale:nil];
178  }
179  
180  - (NSString *)descriptionWithLocale:(id)locale
181  {
182      static CFLocaleRef loc = NULL;
183      static CFDateFormatterRef formatter = NULL;
184      static dispatch_once_t once = 0L;
185      CFDateFormatterRef effectiveFormatter = NULL;
186      CFLocaleRef effectiveLocale = NULL;
187  
188      if (locale && CFGetTypeID(locale) == CFLocaleGetTypeID())
189      {
190          effectiveLocale = (CFLocaleRef)locale;
191      }
192  
193      if (effectiveLocale == NULL)
194      {
195          effectiveLocale = CFLocaleCopyCurrent();
196      }
197  
198      if (loc == NULL)
199      {
200          // Cache the primary locale based formatter
201          loc = (CFLocaleRef)CFRetain(effectiveLocale);
202          dispatch_once(&once, ^{
203              formatter = CFDateFormatterCreate(kCFAllocatorDefault, loc, kCFDateFormatterFullStyle, kCFDateFormatterFullStyle);
204              CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0); // All date descriptions seem to be based off of GMT
205              CFDateFormatterSetProperty(formatter, kCFDateFormatterTimeZone, tz);
206              CFRelease(tz);
207              CFDateFormatterSetFormat(formatter, CFSTR("yyyy-MM-dd HH:mm:ss '+0000'"));
208          });
209      }
210  
211      if (loc == effectiveLocale)
212      {
213          effectiveFormatter = formatter;
214      }
215      else
216      {
217          // cache miss; the locale specified is not the primary locale formatter
218          effectiveFormatter = CFDateFormatterCreate(kCFAllocatorDefault, effectiveLocale, kCFDateFormatterFullStyle, kCFDateFormatterFullStyle);
219          CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0); // All date descriptions seem to be based off of GMT
220          CFDateFormatterSetProperty(effectiveFormatter, kCFDateFormatterTimeZone, tz);
221          CFRelease(tz);
222          CFDateFormatterSetFormat(effectiveFormatter, CFSTR("yyyy-MM-dd HH:mm:ss '+0000'"));
223      }
224  
225      CFStringRef desc = CFDateFormatterCreateStringWithDate(kCFAllocatorDefault, effectiveFormatter, (CFDateRef)self);
226  
227      if (effectiveLocale != locale)
228      {
229          CFRelease(effectiveLocale);
230      }
231  
232      if (effectiveFormatter != formatter)
233      {
234          CFRelease(effectiveFormatter);
235      }
236  
237      return [(NSString *)desc autorelease];
238  }
239  
240  @end
241  
242  @implementation NSDate (NSDateCreation)
243  
244  + (id)date
245  {
246      return [[[self alloc] initWithTimeIntervalSinceReferenceDate:CFAbsoluteTimeGetCurrent()] autorelease];
247  }
248  
249  + (id)dateWithTimeIntervalSinceNow:(NSTimeInterval)ti
250  {
251      return [[[self alloc] initWithTimeIntervalSinceReferenceDate:CFAbsoluteTimeGetCurrent() + ti] autorelease];
252  }
253  
254  + (id)dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti
255  {
256      return [[[self alloc] initWithTimeIntervalSinceReferenceDate:ti] autorelease];
257  }
258  
259  + (id)dateWithTimeIntervalSince1970:(NSTimeInterval)ti
260  {
261      return [[[self alloc] initWithTimeIntervalSinceReferenceDate:ti - NSTimeIntervalSince1970] autorelease];
262  }
263  
264  + (id)dateWithTimeInterval:(NSTimeInterval)ti sinceDate:(NSDate *)date
265  {
266      return [[[self alloc] initWithTimeIntervalSinceReferenceDate:[date timeIntervalSinceReferenceDate] + ti] autorelease];
267  }
268  
269  + (id)distantFuture
270  {
271      static NSDate *distantFuture = nil;
272      static dispatch_once_t onceToken;
273      dispatch_once(&onceToken,
274      ^{
275          distantFuture = [[self alloc] initWithTimeIntervalSinceReferenceDate:NSTimeIntervalDistantFuture];
276      });
277      return distantFuture;
278  }
279  
280  + (id)distantPast
281  {
282      static NSDate *distantPast = nil;
283      static dispatch_once_t onceToken;
284      dispatch_once(&onceToken, 
285      ^{
286          distantPast = [[self alloc] initWithTimeIntervalSinceReferenceDate:NSTimeIntervalDistantPast];
287      });
288      return distantPast;
289  }
290  
291  - (id)init
292  {
293      return [self initWithTimeIntervalSinceReferenceDate:CFAbsoluteTimeGetCurrent()];
294  }
295  
296  - (id)initWithTimeIntervalSinceNow:(NSTimeInterval)ti
297  {
298      return [self initWithTimeIntervalSinceReferenceDate:CFAbsoluteTimeGetCurrent() + ti];
299  }
300  
301  - (id)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti
302  {
303      NSRequestConcreteImplementation();
304      [self release];
305      return nil;
306  }
307  
308  - (id)initWithTimeIntervalSince1970:(NSTimeInterval)ti
309  {
310      return [self initWithTimeIntervalSinceReferenceDate:ti - NSTimeIntervalSince1970];
311  }
312  
313  - (id)initWithTimeInterval:(NSTimeInterval)ti sinceDate:(NSDate *)other
314  {
315      return [self initWithTimeIntervalSinceReferenceDate:ti + [other timeIntervalSinceReferenceDate]];
316  }
317  
318  @end
319  
320  @implementation __NSDate
321  
322  + (id)allocWithZone:(NSZone *)zone
323  {
324      return [__NSPlaceholderDate immutablePlaceholder];
325  }
326  
327  + (id)__new:(NSTimeInterval)t
328  {
329      __NSDate *date = ___CFAllocateObject(self);
330      date->_time = t;
331      return date;
332  }
333  
334  + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
335  {
336      return NO;
337  }
338  
339  - (id)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)t
340  {
341      return (id)[[NSDate alloc] initWithTimeIntervalSinceReferenceDate:t];
342  }
343  
344  - (NSTimeInterval)timeIntervalSinceReferenceDate
345  {
346      return _time;
347  }
348  
349  - (void)dealloc
350  {
351      // this seems strange to implement but it seems to be implemented
352      [super dealloc];
353  }
354  
355  @end
356  
357  @implementation __NSPlaceholderDate
358  
359  + (id)immutablePlaceholder
360  {
361      static dispatch_once_t once = 0L;
362      static __NSPlaceholderDate *immutablePlaceholder = nil;
363      dispatch_once(&once, ^{
364          immutablePlaceholder = [__NSPlaceholderDate alloc];
365      });
366      return immutablePlaceholder;
367  }
368  
369  - (NSTimeInterval)timeIntervalSinceReferenceDate
370  {
371      return 0.0;
372  }
373  
374  SINGLETON_RR()
375  
376  - (id)init
377  {
378      return [self initWithTimeIntervalSinceReferenceDate:CFAbsoluteTimeGetCurrent()];
379  }
380  
381  - (id)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)t
382  {
383      return (id)[__NSDate __new:t];
384  }
385  
386  @end
387  
388  CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at) {
389      return (CFDateRef)[[NSDate alloc] initWithTimeIntervalSinceReferenceDate: (NSTimeInterval)at];
390  }
391  
392  CFTimeInterval CFDateGetAbsoluteTime(CFDateRef date) {
393      return (CFTimeInterval)[(NSDate *)date timeIntervalSinceReferenceDate];
394  }
395  
396  CFTimeInterval CFDateGetTimeIntervalSinceDate(CFDateRef date, CFDateRef otherDate) {
397      return (CFTimeInterval)[(NSDate *)date timeIntervalSinceDate: (NSDate *)otherDate];
398  }
399  
400  CFComparisonResult CFDateCompare(CFDateRef date, CFDateRef otherDate, void *context) {
401      return (CFComparisonResult)[(NSDate *)date compare: (NSDate *)otherDate];
402  }