2001-12-17 14:31:42 +00:00
|
|
|
|
/** Implementation for NSDate for GNUStep
|
1998-12-02 20:16:23 +00:00
|
|
|
|
Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
1995-03-31 15:39:12 +00:00
|
|
|
|
|
1995-04-13 21:57:29 +00:00
|
|
|
|
Written by: Jeremy Bettis <jeremy@hksys.com>
|
1996-10-31 17:14:00 +00:00
|
|
|
|
Rewritten by: Scott Christley <scottc@net-community.com>
|
1995-04-13 21:57:29 +00:00
|
|
|
|
Date: March 1995
|
1998-12-02 20:16:23 +00:00
|
|
|
|
Modifications by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
1995-04-13 21:57:29 +00:00
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1995-03-31 15:39:12 +00:00
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
1995-03-31 15:39:12 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
1995-03-31 15:39:12 +00:00
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2019-12-09 23:36:00 +00:00
|
|
|
|
Lesser General Public License for more details.
|
1995-03-31 15:39:12 +00:00
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
1995-03-31 15:39:12 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2006-06-04 06:42:10 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
2019-12-09 23:36:00 +00:00
|
|
|
|
Boston, MA 02110 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSDate class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
1995-03-31 15:39:12 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
|
#import "common.h"
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "Foundation/NSArray.h"
|
|
|
|
|
#import "Foundation/NSCalendarDate.h"
|
|
|
|
|
#import "Foundation/NSCharacterSet.h"
|
|
|
|
|
#import "Foundation/NSCoder.h"
|
|
|
|
|
#import "Foundation/NSDate.h"
|
|
|
|
|
#import "Foundation/NSDictionary.h"
|
|
|
|
|
#import "Foundation/NSException.h"
|
|
|
|
|
#import "Foundation/NSPortCoder.h"
|
|
|
|
|
#import "Foundation/NSScanner.h"
|
|
|
|
|
#import "Foundation/NSTimeZone.h"
|
|
|
|
|
#import "Foundation/NSUserDefaults.h"
|
|
|
|
|
#import "GNUstepBase/GSObjCRuntime.h"
|
|
|
|
|
|
|
|
|
|
#import "GSPrivate.h"
|
1996-02-13 15:43:30 +00:00
|
|
|
|
|
2008-09-23 08:22:15 +00:00
|
|
|
|
#include <math.h>
|
|
|
|
|
|
2005-03-15 16:40:07 +00:00
|
|
|
|
/* These constants seem to be what MacOS-X uses */
|
|
|
|
|
#define DISTANT_FUTURE 63113990400.0
|
|
|
|
|
#define DISTANT_PAST -63113817600.0
|
1996-03-12 14:48:07 +00:00
|
|
|
|
|
2014-12-23 00:31:46 +00:00
|
|
|
|
/* On older Solaris we don't have NAN nor nan() */
|
|
|
|
|
#if defined(__sun) && defined(__SVR4) && !defined(NAN)
|
|
|
|
|
#define NAN 0x7fffffffffffffff
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-03-26 15:06:49 +00:00
|
|
|
|
GS_DECLARE const NSTimeInterval NSTimeIntervalSince1970 = 978307200.0;
|
2002-11-01 08:11:46 +00:00
|
|
|
|
|
1999-04-23 14:38:03 +00:00
|
|
|
|
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
static BOOL debug = NO;
|
|
|
|
|
static Class abstractClass = nil;
|
|
|
|
|
static Class concreteClass = nil;
|
|
|
|
|
static Class calendarClass = nil;
|
|
|
|
|
|
2002-08-08 19:25:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Our concrete base class - NSCalendar date must share the ivar layout.
|
|
|
|
|
*/
|
|
|
|
|
@interface NSGDate : NSDate
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSTimeInterval _seconds_since_ref;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
1999-04-23 14:38:03 +00:00
|
|
|
|
@interface GSDateSingle : NSGDate
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSDatePast : GSDateSingle
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface GSDateFuture : GSDateSingle
|
|
|
|
|
@end
|
|
|
|
|
|
2011-07-24 13:09:22 +00:00
|
|
|
|
static id _distantPast = nil;
|
|
|
|
|
static id _distantFuture = nil;
|
1999-04-23 14:38:03 +00:00
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
|
1998-12-02 20:16:23 +00:00
|
|
|
|
static NSString*
|
|
|
|
|
findInArray(NSArray *array, unsigned pos, NSString *str)
|
|
|
|
|
{
|
|
|
|
|
unsigned index;
|
|
|
|
|
unsigned limit = [array count];
|
|
|
|
|
|
|
|
|
|
for (index = pos; index < limit; index++)
|
|
|
|
|
{
|
|
|
|
|
NSString *item;
|
|
|
|
|
|
|
|
|
|
item = [array objectAtIndex: index];
|
|
|
|
|
if ([str caseInsensitiveCompare: item] == NSOrderedSame)
|
|
|
|
|
return item;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
static inline NSTimeInterval
|
|
|
|
|
otherTime(NSDate* other)
|
|
|
|
|
{
|
2000-10-31 11:05:23 +00:00
|
|
|
|
Class c;
|
1998-12-02 20:16:23 +00:00
|
|
|
|
|
2000-10-31 11:05:23 +00:00
|
|
|
|
if (other == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException format: @"other time nil"];
|
2000-10-31 16:17:33 +00:00
|
|
|
|
if (GSObjCIsInstance(other) == NO)
|
2000-10-31 11:05:23 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException format: @"other time bad"];
|
2010-02-22 10:13:20 +00:00
|
|
|
|
c = object_getClass(other);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
if (c == concreteClass || c == calendarClass)
|
1999-09-16 07:21:34 +00:00
|
|
|
|
return ((NSGDate*)other)->_seconds_since_ref;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
else
|
|
|
|
|
return [other timeIntervalSinceReferenceDate];
|
|
|
|
|
}
|
1995-03-31 15:39:12 +00:00
|
|
|
|
|
2003-05-16 12:45:02 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* An <code>NSDate</code> object encapsulates a constant date/time to a high
|
|
|
|
|
* resolution represented by the <code>NSTimeInterval</code> typedef.
|
|
|
|
|
* <code>NSDate</code> has methods relating to times and time differences in
|
|
|
|
|
* the abstract, but not calendar dates or time zones. These features are
|
|
|
|
|
* added in the [NSCalendarDate] subclass. The [NSTimeZone] class handles time
|
|
|
|
|
* zone information.
|
2003-05-16 12:45:02 +00:00
|
|
|
|
*/
|
1999-04-19 14:29:52 +00:00
|
|
|
|
@implementation NSDate
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSDate class])
|
|
|
|
|
{
|
|
|
|
|
[self setVersion: 1];
|
|
|
|
|
abstractClass = self;
|
|
|
|
|
concreteClass = [NSGDate class];
|
|
|
|
|
calendarClass = [NSCalendarDate class];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id) alloc
|
|
|
|
|
{
|
|
|
|
|
if (self == abstractClass)
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
return NSAllocateObject(concreteClass, 0, NSDefaultMallocZone());
|
|
|
|
|
}
|
|
|
|
|
return NSAllocateObject(self, 0, NSDefaultMallocZone());
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (self == abstractClass)
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
return NSAllocateObject(concreteClass, 0, z);
|
|
|
|
|
}
|
|
|
|
|
return NSAllocateObject(self, 0, z);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) date
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
2016-10-21 15:32:31 +00:00
|
|
|
|
initWithTimeIntervalSinceReferenceDate: GSPrivateTimeNow()]);
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 21:41:07 +00:00
|
|
|
|
+ (instancetype) now
|
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
|
initWithTimeIntervalSinceReferenceDate: GSPrivateTimeNow()]);
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-16 12:45:02 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns an autoreleased instance representing the date and time given
|
|
|
|
|
* by string. The value of string may be a 'natural' specification as
|
|
|
|
|
* specified by the preferences in the user defaults database, allowing
|
|
|
|
|
* phrases like 'last tuesday'
|
|
|
|
|
*/
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) dateWithNaturalLanguageString: (NSString*)string
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
1999-06-24 19:30:29 +00:00
|
|
|
|
return [self dateWithNaturalLanguageString: string
|
|
|
|
|
locale: nil];
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) dateWithNaturalLanguageString: (NSString*)string
|
|
|
|
|
locale: (NSDictionary*)locale
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
|
|
|
|
NSCharacterSet *ws;
|
|
|
|
|
NSCharacterSet *digits;
|
|
|
|
|
NSScanner *scanner;
|
|
|
|
|
NSString *tmp;
|
|
|
|
|
NSString *dto;
|
|
|
|
|
NSArray *ymw;
|
|
|
|
|
NSMutableArray *words;
|
|
|
|
|
unsigned index;
|
|
|
|
|
unsigned length;
|
|
|
|
|
NSCalendarDate *theDate;
|
|
|
|
|
BOOL hadHour = NO;
|
|
|
|
|
BOOL hadMinute = NO;
|
|
|
|
|
BOOL hadSecond = NO;
|
|
|
|
|
BOOL hadDay = NO;
|
|
|
|
|
BOOL hadMonth = NO;
|
|
|
|
|
BOOL hadYear = NO;
|
|
|
|
|
BOOL hadWeekDay = NO;
|
|
|
|
|
int weekDay = 0;
|
|
|
|
|
int dayOfWeek = 0;
|
|
|
|
|
int modMonth = 0;
|
|
|
|
|
int modYear = 0;
|
|
|
|
|
int modDay = 0;
|
|
|
|
|
int D, M, Y;
|
|
|
|
|
int h = 12;
|
|
|
|
|
int m = 0;
|
|
|
|
|
int s = 0;
|
|
|
|
|
unsigned dtoIndex;
|
|
|
|
|
|
|
|
|
|
if (locale == nil)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
2008-06-07 05:44:58 +00:00
|
|
|
|
locale = GSPrivateDefaultLocale();
|
2002-10-11 09:14:14 +00:00
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
ws = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
|
|
|
|
digits = [NSCharacterSet decimalDigitCharacterSet];
|
|
|
|
|
scanner = [NSScanner scannerWithString: string];
|
|
|
|
|
words = [NSMutableArray arrayWithCapacity: 10];
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
theDate = (NSCalendarDate*)[calendarClass date];
|
1998-12-02 20:16:23 +00:00
|
|
|
|
Y = [theDate yearOfCommonEra];
|
|
|
|
|
M = [theDate monthOfYear];
|
|
|
|
|
D = [theDate dayOfMonth];
|
|
|
|
|
dayOfWeek = [theDate dayOfWeek];
|
|
|
|
|
|
|
|
|
|
[scanner scanCharactersFromSet: ws intoString: 0];
|
|
|
|
|
while ([scanner scanUpToCharactersFromSet: ws intoString: &tmp] == YES)
|
|
|
|
|
{
|
|
|
|
|
[words addObject: tmp];
|
|
|
|
|
[scanner scanCharactersFromSet: ws intoString: 0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Scan the array for day specifications and remove them.
|
|
|
|
|
*/
|
|
|
|
|
if (hadDay == NO)
|
|
|
|
|
{
|
2001-07-10 17:19:18 +00:00
|
|
|
|
NSArray *tdd = [locale objectForKey: NSThisDayDesignations];
|
|
|
|
|
NSArray *ndd = [locale objectForKey: NSNextDayDesignations];
|
|
|
|
|
NSArray *pdd = [locale objectForKey: NSPriorDayDesignations];
|
|
|
|
|
NSArray *nndd = [locale objectForKey: NSNextNextDayDesignations];
|
1998-12-02 20:16:23 +00:00
|
|
|
|
|
|
|
|
|
for (index = 0; hadDay == NO && index < [words count]; index++)
|
|
|
|
|
{
|
|
|
|
|
tmp = [words objectAtIndex: index];
|
|
|
|
|
|
2001-07-10 17:19:18 +00:00
|
|
|
|
if (findInArray(tdd, 0 ,tmp) != nil)
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
|
|
|
|
hadDay = YES;
|
|
|
|
|
}
|
2001-07-10 17:19:18 +00:00
|
|
|
|
else if (findInArray(ndd, 0 ,tmp) != nil)
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
|
|
|
|
modDay++;
|
|
|
|
|
hadDay = YES;
|
|
|
|
|
}
|
2001-07-10 17:19:18 +00:00
|
|
|
|
else if (findInArray(nndd, 0 ,tmp) != nil)
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
|
|
|
|
modDay += 2;
|
|
|
|
|
hadDay = YES;
|
|
|
|
|
}
|
2001-07-10 17:19:18 +00:00
|
|
|
|
else if (findInArray(pdd, 0 ,tmp) != nil)
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
|
|
|
|
modDay--;
|
|
|
|
|
hadDay = YES;
|
|
|
|
|
}
|
|
|
|
|
if (hadDay)
|
|
|
|
|
{
|
|
|
|
|
hadMonth = YES;
|
|
|
|
|
hadYear = YES;
|
|
|
|
|
[words removeObjectAtIndex: index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Scan the array for month specifications and remove them.
|
|
|
|
|
*/
|
|
|
|
|
if (hadMonth == NO)
|
|
|
|
|
{
|
|
|
|
|
NSArray *lm = [locale objectForKey: NSMonthNameArray];
|
|
|
|
|
NSArray *sm = [locale objectForKey: NSShortMonthNameArray];
|
|
|
|
|
|
|
|
|
|
for (index = 0; hadMonth == NO && index < [words count]; index++)
|
|
|
|
|
{
|
|
|
|
|
NSString *mname;
|
|
|
|
|
|
|
|
|
|
tmp = [words objectAtIndex: index];
|
|
|
|
|
|
|
|
|
|
if ((mname = findInArray(lm, 0, tmp)) != nil)
|
|
|
|
|
{
|
2001-07-10 17:43:05 +00:00
|
|
|
|
M = [lm indexOfObjectIdenticalTo: mname] + 1;
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else if ((mname = findInArray(sm, 0, tmp)) != nil)
|
|
|
|
|
{
|
2001-07-10 17:43:05 +00:00
|
|
|
|
M = [sm indexOfObjectIdenticalTo: mname] + 1;
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mname != nil)
|
|
|
|
|
{
|
|
|
|
|
hadMonth = YES;
|
|
|
|
|
[words removeObjectAtIndex: index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Scan the array for weekday specifications and remove them.
|
|
|
|
|
*/
|
|
|
|
|
if (hadWeekDay == NO)
|
|
|
|
|
{
|
|
|
|
|
NSArray *lw = [locale objectForKey: NSWeekDayNameArray];
|
|
|
|
|
NSArray *sw = [locale objectForKey: NSShortWeekDayNameArray];
|
|
|
|
|
|
|
|
|
|
for (index = 0; hadWeekDay == NO && index < [words count]; index++)
|
|
|
|
|
{
|
|
|
|
|
NSString *dname;
|
|
|
|
|
|
|
|
|
|
tmp = [words objectAtIndex: index];
|
|
|
|
|
|
|
|
|
|
if ((dname = findInArray(lw, 0, tmp)) != nil)
|
|
|
|
|
{
|
|
|
|
|
weekDay = [lw indexOfObjectIdenticalTo: dname];
|
|
|
|
|
}
|
|
|
|
|
else if ((dname = findInArray(sw, 0, tmp)) != nil)
|
|
|
|
|
{
|
|
|
|
|
weekDay = [sw indexOfObjectIdenticalTo: dname];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dname != nil)
|
|
|
|
|
{
|
|
|
|
|
hadWeekDay = YES;
|
|
|
|
|
[words removeObjectAtIndex: index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Scan the array for year month week modifiers and remove them.
|
|
|
|
|
* Going by the documentation, these modifiers adjust the date by
|
|
|
|
|
* plus or minus a week, month, or year.
|
|
|
|
|
*/
|
|
|
|
|
ymw = [locale objectForKey: NSYearMonthWeekDesignations];
|
|
|
|
|
if (ymw != nil && [ymw count] > 0)
|
|
|
|
|
{
|
|
|
|
|
unsigned c = [ymw count];
|
|
|
|
|
NSString *yname = [ymw objectAtIndex: 0];
|
|
|
|
|
NSString *mname = c > 1 ? [ymw objectAtIndex: 1] : nil;
|
|
|
|
|
NSArray *early = [locale objectForKey: NSEarlierTimeDesignations];
|
|
|
|
|
NSArray *later = [locale objectForKey: NSLaterTimeDesignations];
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < [words count]; index++)
|
|
|
|
|
{
|
|
|
|
|
tmp = [words objectAtIndex: index];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* See if the current word is a year, month, or week.
|
|
|
|
|
*/
|
|
|
|
|
if (findInArray(ymw, 0, tmp))
|
|
|
|
|
{
|
|
|
|
|
BOOL hadAdjective = NO;
|
|
|
|
|
int adjective = 0;
|
|
|
|
|
NSString *adj = nil;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* See if there is a prefix adjective
|
|
|
|
|
*/
|
|
|
|
|
if (index > 0)
|
|
|
|
|
{
|
|
|
|
|
adj = [words objectAtIndex: index - 1];
|
|
|
|
|
|
|
|
|
|
if (findInArray(early, 0, adj))
|
|
|
|
|
{
|
|
|
|
|
hadAdjective = YES;
|
|
|
|
|
adjective = -1;
|
|
|
|
|
}
|
|
|
|
|
else if (findInArray(later, 0, adj))
|
|
|
|
|
{
|
|
|
|
|
hadAdjective = YES;
|
|
|
|
|
adjective = 1;
|
|
|
|
|
}
|
|
|
|
|
if (hadAdjective)
|
|
|
|
|
{
|
|
|
|
|
[words removeObjectAtIndex: --index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* See if there is a prefix adjective
|
|
|
|
|
*/
|
|
|
|
|
if (hadAdjective == NO && index < [words count] - 1)
|
|
|
|
|
{
|
|
|
|
|
NSString *adj = [words objectAtIndex: index + 1];
|
|
|
|
|
|
|
|
|
|
if (findInArray(early, 0, adj))
|
|
|
|
|
{
|
|
|
|
|
hadAdjective = YES;
|
|
|
|
|
adjective = -1;
|
|
|
|
|
}
|
|
|
|
|
else if (findInArray(later, 0, adj))
|
|
|
|
|
{
|
|
|
|
|
hadAdjective = YES;
|
|
|
|
|
adjective = 1;
|
|
|
|
|
}
|
|
|
|
|
if (hadAdjective)
|
|
|
|
|
{
|
|
|
|
|
[words removeObjectAtIndex: index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Record the adjective information.
|
|
|
|
|
*/
|
|
|
|
|
if (hadAdjective)
|
|
|
|
|
{
|
|
|
|
|
if ([tmp caseInsensitiveCompare: yname] == NSOrderedSame)
|
|
|
|
|
{
|
|
|
|
|
modYear += adjective;
|
|
|
|
|
hadYear = YES;
|
|
|
|
|
}
|
2010-09-10 12:47:04 +00:00
|
|
|
|
else if (mname != nil
|
|
|
|
|
&& [tmp caseInsensitiveCompare: mname] == NSOrderedSame)
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
|
|
|
|
modMonth += adjective;
|
|
|
|
|
hadMonth = YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (hadWeekDay)
|
|
|
|
|
{
|
|
|
|
|
modDay += weekDay - dayOfWeek;
|
|
|
|
|
}
|
|
|
|
|
modDay += 7*adjective;
|
|
|
|
|
hadDay = YES;
|
|
|
|
|
hadMonth = YES;
|
|
|
|
|
hadYear = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Remove from list of words.
|
|
|
|
|
*/
|
|
|
|
|
[words removeObjectAtIndex: index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Scan for hour of the day */
|
|
|
|
|
if (hadHour == NO)
|
|
|
|
|
{
|
|
|
|
|
NSArray *hours = [locale objectForKey: NSHourNameDesignations];
|
|
|
|
|
unsigned hLimit = [hours count];
|
|
|
|
|
unsigned hIndex;
|
|
|
|
|
|
|
|
|
|
for (index = 0; hadHour == NO && index < [words count]; index++)
|
|
|
|
|
{
|
|
|
|
|
tmp = [words objectAtIndex: index];
|
|
|
|
|
|
|
|
|
|
for (hIndex = 0; hadHour == NO && hIndex < hLimit; hIndex++)
|
|
|
|
|
{
|
|
|
|
|
NSArray *names;
|
|
|
|
|
|
|
|
|
|
names = [hours objectAtIndex: hIndex];
|
|
|
|
|
if (findInArray(names, 1, tmp) != nil)
|
|
|
|
|
{
|
|
|
|
|
h = [[names objectAtIndex: 0] intValue];
|
|
|
|
|
hadHour = YES;
|
|
|
|
|
hadMinute = YES;
|
|
|
|
|
hadSecond = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now re-scan the string for numeric information.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
dto = [locale objectForKey: NSDateTimeOrdering];
|
|
|
|
|
if (dto == nil)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"no NSDateTimeOrdering - default to DMYH.");
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
dto = @"DMYH";
|
|
|
|
|
}
|
|
|
|
|
length = [dto length];
|
|
|
|
|
if (length > 4)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"too many characters in NSDateTimeOrdering - truncating.");
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
length = 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dtoIndex = 0;
|
|
|
|
|
scanner = [NSScanner scannerWithString: string];
|
2010-03-04 08:25:52 +00:00
|
|
|
|
[scanner setCaseSensitive: NO];
|
2018-02-06 16:49:07 +00:00
|
|
|
|
// We don't care if there are non-digit characters ... skip if they are there
|
|
|
|
|
(void)[scanner scanUpToCharactersFromSet: digits intoString: 0];
|
1998-12-02 20:16:23 +00:00
|
|
|
|
while ([scanner scanCharactersFromSet: digits intoString: &tmp] == YES)
|
|
|
|
|
{
|
|
|
|
|
int num = [tmp intValue];
|
|
|
|
|
|
|
|
|
|
if ([scanner scanUpToCharactersFromSet: digits intoString: &tmp] == NO)
|
|
|
|
|
{
|
|
|
|
|
tmp = nil;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Numbers separated by colons are a time specification.
|
|
|
|
|
*/
|
|
|
|
|
if (tmp && ([tmp characterAtIndex: 0] == (unichar)':'))
|
|
|
|
|
{
|
|
|
|
|
BOOL done = NO;
|
2010-03-04 08:25:52 +00:00
|
|
|
|
BOOL checkForAMPM = NO;
|
1998-12-02 20:16:23 +00:00
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (hadHour == NO)
|
|
|
|
|
{
|
|
|
|
|
if (num > 23)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"hour (%d) too large - ignored.", num);
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
else
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
h = num;
|
|
|
|
|
m = 0;
|
|
|
|
|
s = 0;
|
|
|
|
|
hadHour = YES;
|
2010-03-03 19:24:56 +00:00
|
|
|
|
checkForAMPM = YES;
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (hadMinute == NO)
|
|
|
|
|
{
|
|
|
|
|
if (num > 59)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"minute (%d) too large - ignored.", num);
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
else
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m = num;
|
|
|
|
|
s = 0;
|
|
|
|
|
hadMinute = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (hadSecond == NO)
|
|
|
|
|
{
|
|
|
|
|
if (num > 59)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"second (%d) too large - ignored.", num);
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
else
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s = num;
|
|
|
|
|
hadSecond = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"odd time spec - excess numbers ignored.");
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done = YES;
|
|
|
|
|
if (tmp && ([tmp characterAtIndex: 0] == (unichar)':'))
|
|
|
|
|
{
|
|
|
|
|
if ([scanner scanCharactersFromSet: digits intoString: &tmp])
|
|
|
|
|
{
|
|
|
|
|
num = [tmp intValue];
|
|
|
|
|
done = NO;
|
2010-03-04 08:25:52 +00:00
|
|
|
|
if ([scanner scanString: @":" intoString: &tmp] == NO)
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
|
|
|
|
tmp = nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (done == NO);
|
2010-03-03 19:24:56 +00:00
|
|
|
|
|
2010-03-04 08:25:52 +00:00
|
|
|
|
if (checkForAMPM)
|
|
|
|
|
{
|
|
|
|
|
NSArray *ampm;
|
|
|
|
|
|
|
|
|
|
ampm = [locale objectForKey: NSAMPMDesignation];
|
|
|
|
|
if ([scanner scanString: [ampm objectAtIndex: 0]
|
|
|
|
|
intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
if (h == 12) // 12 AM means midnight
|
|
|
|
|
h = 0;
|
2010-03-03 19:24:56 +00:00
|
|
|
|
}
|
2010-03-04 08:25:52 +00:00
|
|
|
|
else if ([scanner scanString: [ampm objectAtIndex: 1]
|
|
|
|
|
intoString: NULL])
|
|
|
|
|
{
|
|
|
|
|
if (h < 12) // if PM add 12 to any hour less than 12
|
|
|
|
|
h += 12;
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BOOL mustSkip = YES;
|
|
|
|
|
|
2011-03-09 10:24:18 +00:00
|
|
|
|
while ((dtoIndex < length) && (mustSkip == YES))
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
|
|
|
|
switch ([dto characterAtIndex: dtoIndex])
|
|
|
|
|
{
|
|
|
|
|
case 'D':
|
|
|
|
|
if (hadDay)
|
|
|
|
|
dtoIndex++;
|
|
|
|
|
else
|
|
|
|
|
mustSkip = NO;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'M':
|
|
|
|
|
if (hadMonth)
|
|
|
|
|
dtoIndex++;
|
|
|
|
|
else
|
|
|
|
|
mustSkip = NO;
|
|
|
|
|
break;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
|
1998-12-02 20:16:23 +00:00
|
|
|
|
case 'Y':
|
|
|
|
|
if (hadYear)
|
|
|
|
|
dtoIndex++;
|
|
|
|
|
else
|
|
|
|
|
mustSkip = NO;
|
|
|
|
|
break;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
|
1998-12-02 20:16:23 +00:00
|
|
|
|
case 'H':
|
|
|
|
|
if (hadHour)
|
|
|
|
|
dtoIndex++;
|
|
|
|
|
else
|
|
|
|
|
mustSkip = NO;
|
|
|
|
|
break;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
|
1998-12-02 20:16:23 +00:00
|
|
|
|
default:
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"odd char (unicode %d) in NSDateTimeOrdering.",
|
|
|
|
|
[dto characterAtIndex: dtoIndex]);
|
|
|
|
|
}
|
1999-09-13 04:11:39 +00:00
|
|
|
|
dtoIndex++;
|
1998-12-02 20:16:23 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-09 10:24:18 +00:00
|
|
|
|
if (dtoIndex >= length)
|
1998-12-02 20:16:23 +00:00
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"odd date specification - excess numbers ignored.");
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
switch ([dto characterAtIndex: dtoIndex])
|
|
|
|
|
{
|
|
|
|
|
case 'D':
|
|
|
|
|
if (num < 1)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"day (0) too small - ignored.");
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
else
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else if (num > 31)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"day (%d) too large - ignored.", num);
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
else
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
D = num;
|
|
|
|
|
hadDay = YES;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'M':
|
|
|
|
|
if (num < 1)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"month (0) too small - ignored.");
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
else
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else if (num > 12)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"month (%d) too large - ignored.", num);
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
else
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
M = num;
|
|
|
|
|
hadMonth = YES;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'Y':
|
|
|
|
|
if (num < 100)
|
|
|
|
|
{
|
|
|
|
|
if (num < 70)
|
|
|
|
|
{
|
|
|
|
|
Y = num + 2000;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Y = num + 1900;
|
|
|
|
|
}
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"year (%d) adjusted to %d.", num, Y);
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Y = num;
|
|
|
|
|
}
|
|
|
|
|
hadYear = YES;
|
|
|
|
|
break;
|
|
|
|
|
case 'H':
|
|
|
|
|
{
|
|
|
|
|
BOOL shouldIgnore = NO;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check the next text to see if it is an am/pm
|
|
|
|
|
* designation.
|
|
|
|
|
*/
|
|
|
|
|
if (tmp)
|
|
|
|
|
{
|
|
|
|
|
NSArray *ampm;
|
|
|
|
|
NSString *mod;
|
|
|
|
|
|
|
|
|
|
ampm = [locale objectForKey: NSAMPMDesignation];
|
|
|
|
|
mod = findInArray(ampm, 0, tmp);
|
|
|
|
|
if (mod)
|
|
|
|
|
{
|
|
|
|
|
if (num > 11)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"hour (%d) too large - ignored.", num);
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
else
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
shouldIgnore = YES;
|
|
|
|
|
}
|
|
|
|
|
else if (mod == [ampm objectAtIndex: 1])
|
|
|
|
|
{
|
|
|
|
|
num += 12;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (shouldIgnore == NO)
|
|
|
|
|
{
|
|
|
|
|
if (num > 23)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"hour (%d) too large - ignored.", num);
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
else
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
hadHour = YES;
|
|
|
|
|
h = num;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"unexpected char (unicode%d) in NSDateTimeOrdering.",
|
|
|
|
|
[dto characterAtIndex: dtoIndex]);
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-04-19 14:29:52 +00:00
|
|
|
|
|
1998-12-02 20:16:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we had no date or time information - we give up, otherwise
|
|
|
|
|
* we can use reasonable defaults for any missing info.
|
|
|
|
|
* Missing date => today
|
1999-04-19 14:29:52 +00:00
|
|
|
|
* Missing time => 12: 00
|
1998-12-02 20:16:23 +00:00
|
|
|
|
* If we had a week/month/year modifier without a day, we assume today.
|
|
|
|
|
* If we had a day name without any more day detail - adjust to that
|
|
|
|
|
* day this week.
|
|
|
|
|
*/
|
|
|
|
|
if (hadDay == NO && hadWeekDay == YES)
|
|
|
|
|
{
|
|
|
|
|
modDay += weekDay - dayOfWeek;
|
|
|
|
|
hadDay = YES;
|
|
|
|
|
}
|
|
|
|
|
if (hadDay == NO && hadHour == NO)
|
|
|
|
|
{
|
|
|
|
|
if (modDay == NO && modMonth == NO && modYear == NO)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Build a calendar date we can adjust easily.
|
|
|
|
|
*/
|
1999-04-19 14:29:52 +00:00
|
|
|
|
theDate = [calendarClass dateWithYear: Y
|
1998-12-02 20:16:23 +00:00
|
|
|
|
month: M
|
|
|
|
|
day: D
|
|
|
|
|
hour: h
|
|
|
|
|
minute: m
|
|
|
|
|
second: s
|
|
|
|
|
timeZone: [NSTimeZone defaultTimeZone]];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Adjust the date by year month or days if necessary.
|
|
|
|
|
*/
|
|
|
|
|
if (modYear || modMonth || modDay)
|
|
|
|
|
{
|
|
|
|
|
theDate = [theDate dateByAddingYears: modYear
|
|
|
|
|
months: modMonth
|
|
|
|
|
days: modDay
|
|
|
|
|
hours: 0
|
|
|
|
|
minutes: 0
|
|
|
|
|
seconds: 0];
|
|
|
|
|
}
|
|
|
|
|
if (hadWeekDay && [theDate dayOfWeek] != weekDay)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2002-10-11 09:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"Date resulted in wrong day of week.");
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
2001-05-18 15:25:48 +00:00
|
|
|
|
if (theDate == nil)
|
|
|
|
|
{
|
|
|
|
|
return theDate;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return [self dateWithTimeIntervalSinceReferenceDate:
|
|
|
|
|
otherTime(theDate)];
|
|
|
|
|
}
|
1998-12-02 20:16:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) dateWithString: (NSString*)description
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return AUTORELEASE([[self alloc] initWithString: description]);
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) dateWithTimeInterval: (NSTimeInterval)seconds
|
|
|
|
|
sinceDate: (NSDate*)date
|
1998-01-21 14:56:24 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return AUTORELEASE([[self alloc] initWithTimeInterval: seconds
|
|
|
|
|
sinceDate: date]);
|
1998-01-21 14:56:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) dateWithTimeIntervalSince1970: (NSTimeInterval)seconds
|
1996-10-31 17:14:00 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return AUTORELEASE([[self alloc] initWithTimeIntervalSinceReferenceDate:
|
2016-10-21 15:32:31 +00:00
|
|
|
|
seconds - NSTimeIntervalSince1970]);
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) dateWithTimeIntervalSinceNow: (NSTimeInterval)seconds
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([[self alloc] initWithTimeIntervalSinceNow: seconds]);
|
1996-10-31 17:14:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) dateWithTimeIntervalSinceReferenceDate: (NSTimeInterval)seconds
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return AUTORELEASE([[self alloc] initWithTimeIntervalSinceReferenceDate:
|
|
|
|
|
seconds]);
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) distantPast
|
2013-10-14 22:30:33 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (_distantPast == nil)
|
|
|
|
|
{
|
|
|
|
|
_distantPast = [GSDatePast allocWithZone: 0];
|
|
|
|
|
}
|
|
|
|
|
return _distantPast;
|
2013-10-14 22:30:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
+ (instancetype) distantFuture
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
1999-04-23 14:38:03 +00:00
|
|
|
|
if (_distantFuture == nil)
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
_distantFuture = [GSDateFuture allocWithZone: 0];
|
|
|
|
|
}
|
1999-04-23 14:38:03 +00:00
|
|
|
|
return _distantFuture;
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-05-16 12:45:02 +00:00
|
|
|
|
/**
|
2016-10-21 15:32:31 +00:00
|
|
|
|
* Returns the time interval between the current date and the
|
|
|
|
|
* reference date (1 January 2001, GMT).
|
2003-05-16 12:45:02 +00:00
|
|
|
|
*/
|
2016-10-21 15:32:31 +00:00
|
|
|
|
+ (NSTimeInterval) timeIntervalSinceReferenceDate
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return GSPrivateTimeNow();
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
- (instancetype) addTimeInterval: (NSTimeInterval)seconds
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
return [self dateByAddingTimeInterval: seconds];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSComparisonResult) compare: (NSDate*)otherDate
|
|
|
|
|
{
|
|
|
|
|
if (otherDate == self)
|
|
|
|
|
{
|
|
|
|
|
return NSOrderedSame;
|
|
|
|
|
}
|
|
|
|
|
if (otherTime(self) > otherTime(otherDate))
|
|
|
|
|
{
|
|
|
|
|
return NSOrderedDescending;
|
|
|
|
|
}
|
|
|
|
|
if (otherTime(self) < otherTime(otherDate))
|
|
|
|
|
{
|
|
|
|
|
return NSOrderedAscending;
|
|
|
|
|
}
|
|
|
|
|
return NSOrderedSame;
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
if (NSShouldRetainWithZone(self, zone))
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
return RETAIN(self);
|
|
|
|
|
}
|
|
|
|
|
return NSCopyObject(self, 0, zone);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
|
- (Class) classForCoder
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return abstractClass;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
- (instancetype) dateByAddingTimeInterval: (NSTimeInterval)ti
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return [[self class] dateWithTimeIntervalSinceReferenceDate:
|
|
|
|
|
otherTime(self) + ti];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSCalendarDate *) dateWithCalendarFormat: (NSString*)formatString
|
|
|
|
|
timeZone: (NSTimeZone*)timeZone
|
|
|
|
|
{
|
|
|
|
|
NSCalendarDate *d = [calendarClass alloc];
|
|
|
|
|
|
|
|
|
|
d = [d initWithTimeIntervalSinceReferenceDate: otherTime(self)];
|
|
|
|
|
[d setCalendarFormat: formatString];
|
|
|
|
|
[d setTimeZone: timeZone];
|
|
|
|
|
return AUTORELEASE(d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) description
|
|
|
|
|
{
|
|
|
|
|
// Easiest to just have NSCalendarDate do the work for us
|
|
|
|
|
NSString *s;
|
|
|
|
|
NSCalendarDate *d = [calendarClass alloc];
|
|
|
|
|
|
|
|
|
|
d = [d initWithTimeIntervalSinceReferenceDate: otherTime(self)];
|
|
|
|
|
s = [d description];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) descriptionWithCalendarFormat: (NSString*)format
|
|
|
|
|
timeZone: (NSTimeZone*)aTimeZone
|
|
|
|
|
locale: (NSDictionary*)l
|
|
|
|
|
{
|
|
|
|
|
// Easiest to just have NSCalendarDate do the work for us
|
|
|
|
|
NSString *s;
|
|
|
|
|
NSCalendarDate *d = [calendarClass alloc];
|
|
|
|
|
id f;
|
|
|
|
|
|
|
|
|
|
d = [d initWithTimeIntervalSinceReferenceDate: otherTime(self)];
|
|
|
|
|
if (!format)
|
|
|
|
|
{
|
|
|
|
|
f = [d calendarFormat];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
f = format;
|
|
|
|
|
}
|
|
|
|
|
if (aTimeZone)
|
|
|
|
|
{
|
|
|
|
|
[d setTimeZone: aTimeZone];
|
|
|
|
|
}
|
|
|
|
|
s = [d descriptionWithCalendarFormat: f locale: l];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *) descriptionWithLocale: (id)locale
|
|
|
|
|
{
|
|
|
|
|
// Easiest to just have NSCalendarDate do the work for us
|
|
|
|
|
NSString *s;
|
|
|
|
|
NSCalendarDate *d = [calendarClass alloc];
|
|
|
|
|
|
|
|
|
|
d = [d initWithTimeIntervalSinceReferenceDate: otherTime(self)];
|
|
|
|
|
s = [d descriptionWithLocale: locale];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSDate*) earlierDate: (NSDate*)otherDate
|
|
|
|
|
{
|
|
|
|
|
if (otherTime(self) > otherTime(otherDate))
|
|
|
|
|
{
|
|
|
|
|
return otherDate;
|
|
|
|
|
}
|
|
|
|
|
return self;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)coder
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSTimeInterval interval = [self timeIntervalSinceReferenceDate];
|
|
|
|
|
|
2008-10-12 19:08:24 +00:00
|
|
|
|
if ([coder allowsKeyedCoding])
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
[coder encodeDouble: interval forKey: @"NS.time"];
|
|
|
|
|
}
|
|
|
|
|
[coder encodeValueOfObjCType: @encode(NSTimeInterval) at: &interval];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSUInteger) hash
|
|
|
|
|
{
|
|
|
|
|
return (NSUInteger)[self timeIntervalSinceReferenceDate];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
- (instancetype) initWithCoder: (NSCoder*)coder
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSTimeInterval interval;
|
|
|
|
|
id o;
|
|
|
|
|
|
2008-10-12 19:08:24 +00:00
|
|
|
|
if ([coder allowsKeyedCoding])
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
interval = [coder decodeDoubleForKey: @"NS.time"];
|
|
|
|
|
}
|
2008-10-12 19:08:24 +00:00
|
|
|
|
else
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
[coder decodeValueOfObjCType: @encode(NSTimeInterval) at: &interval];
|
|
|
|
|
}
|
2000-10-16 12:35:42 +00:00
|
|
|
|
if (interval == DISTANT_PAST)
|
|
|
|
|
{
|
|
|
|
|
o = RETAIN([abstractClass distantPast]);
|
|
|
|
|
}
|
|
|
|
|
else if (interval == DISTANT_FUTURE)
|
|
|
|
|
{
|
|
|
|
|
o = RETAIN([abstractClass distantFuture]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
o = [concreteClass allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
o = [o initWithTimeIntervalSinceReferenceDate: interval];
|
|
|
|
|
}
|
2010-02-25 18:49:31 +00:00
|
|
|
|
DESTROY(self);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return o;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
- (instancetype) init
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2010-12-27 07:03:50 +00:00
|
|
|
|
return [self initWithTimeIntervalSinceReferenceDate: GSPrivateTimeNow()];
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
- (instancetype) initWithString: (NSString*)description
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
1996-10-31 17:14:00 +00:00
|
|
|
|
// Easiest to just have NSCalendarDate do the work for us
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSCalendarDate *d = [calendarClass alloc];
|
|
|
|
|
|
2000-04-05 21:43:40 +00:00
|
|
|
|
d = [d initWithString: description];
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (nil == d)
|
2001-05-18 15:25:48 +00:00
|
|
|
|
{
|
2010-02-25 18:49:31 +00:00
|
|
|
|
DESTROY(self);
|
2001-05-18 15:25:48 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
self = [self initWithTimeIntervalSinceReferenceDate: otherTime(d)];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
return self;
|
|
|
|
|
}
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
- (instancetype) initWithTimeInterval: (NSTimeInterval)secsToBeAdded
|
|
|
|
|
sinceDate: (NSDate*)anotherDate
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2001-05-18 15:25:48 +00:00
|
|
|
|
if (anotherDate == nil)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"initWithTimeInterval:sinceDate: given nil date");
|
2010-02-25 18:49:31 +00:00
|
|
|
|
DESTROY(self);
|
2001-05-18 15:25:48 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
1996-10-31 17:14:00 +00:00
|
|
|
|
// Get the other date's time, add the secs and init thyself
|
1995-04-13 21:57:29 +00:00
|
|
|
|
return [self initWithTimeIntervalSinceReferenceDate:
|
2001-05-18 15:25:48 +00:00
|
|
|
|
otherTime(anotherDate) + secsToBeAdded];
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
- (instancetype) initWithTimeIntervalSince1970: (NSTimeInterval)seconds
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
1995-04-13 21:57:29 +00:00
|
|
|
|
return [self initWithTimeIntervalSinceReferenceDate:
|
2016-10-21 15:32:31 +00:00
|
|
|
|
seconds - NSTimeIntervalSince1970];
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
- (instancetype) initWithTimeIntervalSinceNow: (NSTimeInterval)secsToBeAdded
|
1997-03-03 20:07:35 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
// Get the current time, add the secs and init thyself
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return [self initWithTimeIntervalSinceReferenceDate:
|
2016-10-21 15:32:31 +00:00
|
|
|
|
GSPrivateTimeNow() + secsToBeAdded];
|
1997-03-03 20:07:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 13:31:45 +00:00
|
|
|
|
- (instancetype) initWithTimeIntervalSinceReferenceDate: (NSTimeInterval)secs
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
1996-10-31 17:14:00 +00:00
|
|
|
|
return self;
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (BOOL) isEqual: (id)other
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (other != nil
|
|
|
|
|
&& [other isKindOfClass: abstractClass]
|
|
|
|
|
&& otherTime(self) == otherTime(other))
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
1995-08-08 15:46:04 +00:00
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (BOOL) isEqualToDate: (NSDate*)other
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (other != nil
|
|
|
|
|
&& otherTime(self) == otherTime(other))
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
1995-08-08 15:46:04 +00:00
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (NSDate*) laterDate: (NSDate*)otherDate
|
1996-10-31 17:14:00 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (otherTime(self) < otherTime(otherDate))
|
|
|
|
|
{
|
|
|
|
|
return otherDate;
|
|
|
|
|
}
|
|
|
|
|
return self;
|
1996-10-31 17:14:00 +00:00
|
|
|
|
}
|
1995-03-31 15:39:12 +00:00
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if ([aCoder isByref] == NO)
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
return [super replacementObjectForPortCoder: aCoder];
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSTimeInterval) timeIntervalSince1970
|
|
|
|
|
{
|
2002-11-01 08:11:46 +00:00
|
|
|
|
return otherTime(self) + NSTimeIntervalSince1970;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSTimeInterval) timeIntervalSinceDate: (NSDate*)otherDate
|
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (nil == otherDate)
|
|
|
|
|
{
|
2013-05-17 18:38:19 +00:00
|
|
|
|
#ifndef NAN
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return nan("");
|
2013-05-17 18:38:19 +00:00
|
|
|
|
#else
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return NAN;
|
2013-05-17 18:38:19 +00:00
|
|
|
|
#endif
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return otherTime(self) - otherTime(otherDate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSTimeInterval) timeIntervalSinceNow
|
|
|
|
|
{
|
2010-12-27 07:03:50 +00:00
|
|
|
|
return otherTime(self) - GSPrivateTimeNow();
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSTimeInterval) timeIntervalSinceReferenceDate
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSGDate
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSDate class])
|
|
|
|
|
{
|
|
|
|
|
[self setVersion: 1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
- (NSComparisonResult) compare: (NSDate*)otherDate
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
if (otherDate == self)
|
|
|
|
|
{
|
|
|
|
|
return NSOrderedSame;
|
|
|
|
|
}
|
|
|
|
|
if (otherDate == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"nil argument for compare:"];
|
|
|
|
|
}
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (_seconds_since_ref > otherTime(otherDate))
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
|
|
|
|
return NSOrderedDescending;
|
|
|
|
|
}
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (_seconds_since_ref < otherTime(otherDate))
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
|
|
|
|
return NSOrderedAscending;
|
|
|
|
|
}
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return NSOrderedSame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSDate*) earlierDate: (NSDate*)otherDate
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
if (otherDate == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"nil argument for earlierDate:"];
|
|
|
|
|
}
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (_seconds_since_ref > otherTime(otherDate))
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return otherDate;
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)coder
|
1999-04-19 14:29:52 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if ([coder allowsKeyedCoding])
|
1999-04-19 14:29:52 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
[coder encodeDouble:_seconds_since_ref forKey:@"NS.time"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[coder encodeValueOfObjCType: @encode(NSTimeInterval)
|
|
|
|
|
at: &_seconds_since_ref];
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (NSUInteger) hash
|
1999-04-19 14:29:52 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return (unsigned)_seconds_since_ref;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithCoder: (NSCoder*)coder
|
|
|
|
|
{
|
2008-10-12 19:08:24 +00:00
|
|
|
|
if ([coder allowsKeyedCoding])
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
_seconds_since_ref = [coder decodeDoubleForKey: @"NS.time"];
|
|
|
|
|
}
|
2008-10-12 19:08:24 +00:00
|
|
|
|
else
|
2016-10-21 15:32:31 +00:00
|
|
|
|
{
|
|
|
|
|
[coder decodeValueOfObjCType: @encode(NSTimeInterval)
|
|
|
|
|
at: &_seconds_since_ref];
|
|
|
|
|
}
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithTimeIntervalSinceReferenceDate: (NSTimeInterval)secs
|
|
|
|
|
{
|
2008-09-23 08:22:15 +00:00
|
|
|
|
if (isnan(secs))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@-%@] interval is not a number",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
2016-03-15 19:04:51 +00:00
|
|
|
|
|
|
|
|
|
#if GS_SIZEOF_VOIDP == 4
|
|
|
|
|
if (secs <= DISTANT_PAST)
|
|
|
|
|
{
|
|
|
|
|
secs = DISTANT_PAST;
|
|
|
|
|
}
|
|
|
|
|
else if (secs >= DISTANT_FUTURE)
|
|
|
|
|
{
|
|
|
|
|
secs = DISTANT_FUTURE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_seconds_since_ref = secs;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (BOOL) isEqual: (id)other
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (other != nil
|
|
|
|
|
&& [other isKindOfClass: abstractClass]
|
|
|
|
|
&& _seconds_since_ref == otherTime(other))
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return YES;
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return NO;
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (BOOL) isEqualToDate: (NSDate*)other
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (other != nil
|
|
|
|
|
&& _seconds_since_ref == otherTime(other))
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (NSDate*) laterDate: (NSDate*)otherDate
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
if (otherDate == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2016-10-21 15:32:31 +00:00
|
|
|
|
format: @"nil argument for laterDate:"];
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_seconds_since_ref < otherTime(otherDate))
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return otherDate;
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
1995-04-13 21:57:29 +00:00
|
|
|
|
return self;
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (NSTimeInterval) timeIntervalSince1970
|
2004-05-24 15:30:11 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return _seconds_since_ref + NSTimeIntervalSince1970;
|
2004-05-24 15:30:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (NSTimeInterval) timeIntervalSinceDate: (NSDate*)otherDate
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
if (otherDate == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"nil argument for timeIntervalSinceDate:"];
|
|
|
|
|
}
|
|
|
|
|
return _seconds_since_ref - otherTime(otherDate);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
1995-03-31 15:39:12 +00:00
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (NSTimeInterval) timeIntervalSinceNow
|
1998-11-30 10:04:24 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return _seconds_since_ref - GSPrivateTimeNow();
|
1999-04-19 14:29:52 +00:00
|
|
|
|
}
|
1998-11-30 10:04:24 +00:00
|
|
|
|
|
2016-10-21 15:32:31 +00:00
|
|
|
|
- (NSTimeInterval) timeIntervalSinceReferenceDate
|
1995-03-31 15:39:12 +00:00
|
|
|
|
{
|
2016-10-21 15:32:31 +00:00
|
|
|
|
return _seconds_since_ref;
|
1995-03-31 15:39:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
1999-04-19 14:29:52 +00:00
|
|
|
|
|
1999-04-23 14:38:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This abstract class represents a date of which there can be only
|
|
|
|
|
* one instance.
|
|
|
|
|
*/
|
|
|
|
|
@implementation GSDateSingle
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [GSDateSingle class])
|
|
|
|
|
{
|
|
|
|
|
[self setVersion: 1];
|
2002-11-27 12:52:29 +00:00
|
|
|
|
GSObjCAddClassBehavior(self, [NSGDate class]);
|
1999-04-23 14:38:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-24 09:28:32 +00:00
|
|
|
|
- (id) autorelease
|
1999-04-23 14:38:03 +00:00
|
|
|
|
{
|
1999-04-24 09:28:32 +00:00
|
|
|
|
return self;
|
1999-04-23 14:38:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-07-31 15:31:39 +00:00
|
|
|
|
- (oneway void) release
|
1999-04-23 14:38:03 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
1999-04-23 14:38:03 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Attempt to allocate fixed date"];
|
1999-06-24 19:30:29 +00:00
|
|
|
|
return nil;
|
1999-04-23 14:38:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Attempt to deallocate fixed date"];
|
2006-06-04 06:42:10 +00:00
|
|
|
|
GSNOSUPERDEALLOC;
|
1999-04-23 14:38:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithTimeIntervalSinceReferenceDate: (NSTimeInterval)secs
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation GSDatePast
|
|
|
|
|
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (_distantPast == nil)
|
|
|
|
|
{
|
|
|
|
|
id obj = NSAllocateObject(self, 0, NSDefaultMallocZone());
|
|
|
|
|
|
|
|
|
|
_distantPast = [obj init];
|
|
|
|
|
}
|
|
|
|
|
return _distantPast;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithTimeIntervalSinceReferenceDate: (NSTimeInterval)secs
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_seconds_since_ref = DISTANT_PAST;
|
1999-04-23 14:38:03 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation GSDateFuture
|
|
|
|
|
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (_distantFuture == nil)
|
|
|
|
|
{
|
|
|
|
|
id obj = NSAllocateObject(self, 0, NSDefaultMallocZone());
|
|
|
|
|
|
|
|
|
|
_distantFuture = [obj init];
|
|
|
|
|
}
|
|
|
|
|
return _distantFuture;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithTimeIntervalSinceReferenceDate: (NSTimeInterval)secs
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_seconds_since_ref = DISTANT_FUTURE;
|
1999-04-23 14:38:03 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|