@@ -18,10 +18,13 @@ #define _GNU_SOURCE #include #include #include +#include +#include +#include #include #import "OFDate.h" #import "OFString.h" @@ -47,11 +50,11 @@ #ifdef HAVE_GMTIME_R # define GMTIME_RET(field) \ time_t seconds_ = (time_t)seconds; \ struct tm tm; \ \ - if (seconds != seconds_) \ + if (seconds_ != floor(seconds)) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ if (gmtime_r(&seconds_, &tm) == NULL) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ @@ -58,11 +61,11 @@ return tm.field; # define LOCALTIME_RET(field) \ time_t seconds_ = (time_t)seconds; \ struct tm tm; \ \ - if (seconds != seconds_) \ + if (seconds_ != floor(seconds)) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ if (localtime_r(&seconds_, &tm) == NULL) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ @@ -71,11 +74,11 @@ # ifdef OF_THREADS # define GMTIME_RET(field) \ time_t seconds_ = (time_t)seconds; \ struct tm *tm; \ \ - if (seconds != seconds_) \ + if (seconds_ != floor(seconds)) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ [mutex lock]; \ \ @try { \ @@ -88,11 +91,11 @@ } # define LOCALTIME_RET(field) \ time_t seconds_ = (time_t)seconds; \ struct tm *tm; \ \ - if (seconds != seconds_) \ + if (seconds_ != floor(seconds)) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ [mutex lock]; \ \ @try { \ @@ -106,11 +109,11 @@ # else # define GMTIME_RET(field) \ time_t seconds_ = (time_t)seconds; \ struct tm *tm; \ \ - if (seconds != seconds_) \ + if (seconds_ != floor(seconds)) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ if ((tm = gmtime(&seconds_)) == NULL) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ @@ -117,11 +120,11 @@ return tm->field; # define LOCALTIME_RET(field) \ time_t seconds_ = (time_t)seconds; \ struct tm *tm; \ \ - if (seconds != seconds_) \ + if (seconds_ != floor(seconds)) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ if ((tm = localtime(&seconds_)) == NULL) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ @@ -142,38 +145,22 @@ + date { return [[[self alloc] init] autorelease]; } -+ dateWithTimeIntervalSince1970: (int64_t)seconds ++ dateWithTimeIntervalSince1970: (double)seconds { return [[[self alloc] initWithTimeIntervalSince1970: seconds] autorelease]; } -+ dateWithTimeIntervalSince1970: (int64_t)seconds - microseconds: (uint32_t)microseconds -{ - return [[[self alloc] - initWithTimeIntervalSince1970: seconds - microseconds: microseconds] autorelease]; -} - -+ dateWithTimeIntervalSinceNow: (int64_t)seconds ++ dateWithTimeIntervalSinceNow: (double)seconds { return [[[self alloc] initWithTimeIntervalSinceNow: seconds] autorelease]; } -+ dateWithTimeIntervalSinceNow: (int64_t)seconds - microseconds: (uint32_t)microseconds -{ - return [[[self alloc] - initWithTimeIntervalSinceNow: seconds - microseconds: microseconds] autorelease]; -} - + dateWithDateString: (OFString*)string format: (OFString*)format { return [[[self alloc] initWithDateString: string format: format] autorelease]; @@ -186,78 +173,48 @@ format: format] autorelease]; } + distantFuture { - if (sizeof(time_t) == sizeof(int64_t)) - return [[[self alloc] - initWithTimeIntervalSince1970: INT64_MAX - microseconds: 999999] autorelease]; - if (sizeof(time_t) == sizeof(int32_t)) - return [[[self alloc] - initWithTimeIntervalSince1970: INT32_MAX - microseconds: 999999] autorelease]; - - /* Neither 64 nor 32 bit. But it's guaranteed to be at least an int */ - return [[[self alloc] - initWithTimeIntervalSince1970: INT_MAX - microseconds: 999999] autorelease]; + return [[[self alloc] + initWithTimeIntervalSince1970: DBL_MAX] autorelease]; } + distantPast { - /* We don't know if time_t is signed or unsigned. Use 0 to be safe */ - return [[[self alloc] initWithTimeIntervalSince1970: 0] autorelease]; + return [[[self alloc] + initWithTimeIntervalSince1970: DBL_MIN] autorelease]; } - init { struct timeval t; - if (gettimeofday(&t, NULL)) { - Class c = isa; - [self release]; - @throw [OFInitializationFailedException newWithClass: c]; - } - - return [self initWithTimeIntervalSince1970: t.tv_sec - microseconds: (uint32_t)t.tv_usec]; -} - -- initWithTimeIntervalSince1970: (int64_t)seconds_ -{ - return [self initWithTimeIntervalSince1970: seconds_ - microseconds: 0]; -} - -- initWithTimeIntervalSince1970: (int64_t)seconds_ - microseconds: (uint32_t)microseconds_ + self = [super init]; + + assert(!gettimeofday(&t, NULL)); + + seconds = t.tv_sec; + seconds += (double)t.tv_usec / 1000000; + + return self; +} + +- initWithTimeIntervalSince1970: (double)seconds_ { self = [super init]; seconds = seconds_; - microseconds = microseconds_; return self; } -- initWithTimeIntervalSinceNow: (int64_t)seconds_ -{ - return [self initWithTimeIntervalSinceNow: seconds_ - microseconds: 0]; -} - -- initWithTimeIntervalSinceNow: (int64_t)seconds_ - microseconds: (uint32_t)microseconds_ +- initWithTimeIntervalSinceNow: (double)seconds_ { self = [self init]; seconds += seconds_; - microseconds += microseconds_; - - seconds += microseconds / 1000000; - microseconds %= 1000000; return self; } - initWithDateString: (OFString*)string @@ -317,27 +274,17 @@ { self = [super init]; @try { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFXMLAttribute *secondsAttribute, *microsecondsAttribute; if (![[element name] isEqual: [self className]] || ![[element namespace] isEqual: OF_SERIALIZATION_NS]) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; - secondsAttribute = [element attributeForName: @"seconds"]; - microsecondsAttribute = - [element attributeForName: @"microseconds"]; - - if (secondsAttribute == nil || microsecondsAttribute == nil) - @throw [OFInvalidArgumentException newWithClass: isa - selector: _cmd]; - - seconds = (int64_t)[secondsAttribute decimalValue]; - microseconds = (uint32_t)[microsecondsAttribute decimalValue]; + seconds = [element doubleValue]; [pool release]; } @catch (id e) { [self release]; @throw e; @@ -353,25 +300,31 @@ if (![object isKindOfClass: [OFDate class]]) return NO; otherDate = object; - if (otherDate->seconds != seconds || - otherDate->microseconds != microseconds) + if (otherDate->seconds != seconds) return NO; return YES; } - (uint32_t)hash { uint32_t hash; + union { + double d; + uint8_t b[sizeof(double)]; + } d; + uint8_t i; + + d.d = of_bswap_double_if_le(seconds); OF_HASH_INIT(hash); - OF_HASH_ADD_INT64(hash, seconds); - OF_HASH_ADD_INT32(hash, microseconds); + for (i = 0; i < sizeof(double); i++) + OF_HASH_ADD(hash, d.b[i]); OF_HASH_FINALIZE(hash); return hash; } @@ -394,15 +347,10 @@ if (seconds < otherDate->seconds) return OF_ORDERED_ASCENDING; if (seconds > otherDate->seconds) return OF_ORDERED_DESCENDING; - if (microseconds < otherDate->microseconds) - return OF_ORDERED_ASCENDING; - if (microseconds > otherDate->microseconds) - return OF_ORDERED_DESCENDING; - return OF_ORDERED_SAME; } - (OFString*)description { @@ -411,23 +359,14 @@ - (OFXMLElement*)XMLElementBySerializing { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFXMLElement *element; - OFString *secondsString, *microsecondsString; element = [OFXMLElement elementWithName: [self className] namespace: OF_SERIALIZATION_NS]; - - secondsString = [OFString stringWithFormat: @"%" @PRId64, seconds]; - microsecondsString = [OFString stringWithFormat: @"%" @PRIu32, - microseconds]; - - [element addAttributeWithName: @"seconds" - stringValue: secondsString]; - [element addAttributeWithName: @"microseconds" - stringValue: microsecondsString]; + [element setStringValue: [OFString stringWithFormat: @"%la", seconds]]; [element retain]; [pool release]; [element autorelease]; @@ -434,11 +373,11 @@ return element; } - (uint32_t)microsecond { - return microseconds; + return nearbyint(remainder(seconds, 1) * 1000000); } - (uint8_t)second { GMTIME_RET(tm_sec) @@ -514,11 +453,11 @@ OFString *ret; time_t seconds_ = (time_t)seconds; struct tm tm; char *buffer; - if (seconds != seconds_) + if (seconds_ != floor(seconds)) @throw [OFOutOfRangeException newWithClass: isa]; #ifdef HAVE_GMTIME_R if (gmtime_r(&seconds_, &tm) == NULL) @throw [OFOutOfRangeException newWithClass: isa]; @@ -560,11 +499,11 @@ OFString *ret; time_t seconds_ = (time_t)seconds; struct tm tm; char *buffer; - if (seconds != seconds_) + if (seconds_ != floor(seconds)) @throw [OFOutOfRangeException newWithClass: isa]; #ifdef HAVE_LOCALTIME_R if (localtime_r(&seconds_, &tm) == NULL) @throw [OFOutOfRangeException newWithClass: isa]; @@ -615,62 +554,33 @@ return [[otherDate retain] autorelease]; return [[self retain] autorelease]; } -- (int64_t)timeIntervalSince1970 +- (double)timeIntervalSince1970 { return seconds; } -- (uint32_t)microsecondsOfTimeIntervalSince1970 -{ - return microseconds; -} - -- (int64_t)timeIntervalSinceDate: (OFDate*)otherDate -{ - int64_t seconds_ = seconds - otherDate->seconds; - int32_t microseconds_ = (int32_t)microseconds - otherDate->microseconds; - - seconds_ += microseconds_ / 1000000; - microseconds_ %= 1000000; - - while (microseconds_ < 0) { - microseconds_ += 1000000; - seconds_--; - } - - return seconds_; -} - -- (uint32_t)microsecondsOfTimeIntervalSinceDate: (OFDate*)otherDate -{ - int32_t microseconds_ = (int32_t)microseconds - otherDate->microseconds; - - microseconds_ %= 1000000; - - while (microseconds_ < 0) - microseconds_ += 1000000; - - return microseconds_; -} - -- (OFDate*)dateByAddingTimeInterval: (int64_t)sec_ -{ - return [self dateByAddingTimeInterval: sec_ - withMicroseconds: 0]; -} - -- (OFDate*)dateByAddingTimeInterval: (int64_t)seconds_ - withMicroseconds: (uint32_t)microseconds_ -{ - seconds_ += seconds; - microseconds_ += microseconds; - - seconds_ += microseconds_ / 1000000; - microseconds_ %= 1000000; - - return [OFDate dateWithTimeIntervalSince1970: seconds_ - microseconds: microseconds_]; +- (double)timeIntervalSinceDate: (OFDate*)otherDate +{ + return seconds - otherDate->seconds; +} + +- (double)timeIntervalSinceNow +{ + struct timeval t; + double seconds_; + + assert(!gettimeofday(&t, NULL)); + + seconds_ = t.tv_sec; + seconds_ += (double)t.tv_usec / 1000000; + + return seconds - seconds_; +} + +- (OFDate*)dateByAddingTimeInterval: (double)seconds_ +{ + return [OFDate dateWithTimeIntervalSince1970: seconds + seconds_]; } @end