/ 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 }