Index: src/OFDate.h ================================================================== --- src/OFDate.h +++ src/OFDate.h @@ -23,12 +23,11 @@ /** * \brief A class for storing, accessing and comparing dates. */ @interface OFDate: OFObject { - int64_t seconds; - uint32_t microseconds; + double seconds; } /** * \brief Creates a new OFDate with the current date and time. * @@ -41,40 +40,19 @@ * 1970-01-01T00:00:00Z. * * \param seconds The seconds since 1970-01-01T00:00:00Z * \return A new, autoreleased OFDate with the specified date and time */ -+ dateWithTimeIntervalSince1970: (int64_t)seconds; - -/** - * \brief Creates a new OFDate with the specified date and time since - * 1970-01-01T00:00:00Z. - * - * \param seconds The seconds since 1970-01-01T00:00:00Z - * \param microseconds The microsecond part of the time - * \return A new, autoreleased OFDate with the specified date and time - */ -+ dateWithTimeIntervalSince1970: (int64_t)seconds - microseconds: (uint32_t)microseconds; ++ dateWithTimeIntervalSince1970: (double)seconds; /** * \brief Creates a new OFDate with the specified date and time since now. * * \param seconds The seconds since now * \return A new, autoreleased OFDate with the specified date and time */ -+ dateWithTimeIntervalSinceNow: (int64_t)seconds; - -/** - * \brief Creates a new OFDate with the specified date and time since now. - * - * \param seconds The seconds since now - * \param microseconds The microsecond part of the time - * \return A new, autoreleased OFDate with the specified date and time - */ -+ dateWithTimeIntervalSinceNow: (int64_t)seconds - microseconds: (uint32_t)microseconds; ++ dateWithTimeIntervalSinceNow: (double)seconds; /** * \brief Creates a new OFDate with the specified string in the specified * format. * @@ -129,42 +107,20 @@ * time since 1970-01-01T00:00:00Z. * * \param seconds The seconds since 1970-01-01T00:00:00Z * \return An initialized OFDate with the specified date and time */ -- initWithTimeIntervalSince1970: (int64_t)seconds; - -/** - * \brief Initializes an already allocated OFDate with the specified date and - * time since 1970-01-01T00:00:00Z. - * - * \param seconds The seconds since 1970-01-01T00:00:00Z - * \param microseconds The microsecond part of the time - * \return An initialized OFDate with the specified date and time - */ -- initWithTimeIntervalSince1970: (int64_t)seconds - microseconds: (uint32_t)microseconds; +- initWithTimeIntervalSince1970: (double)seconds; /** * \brief Initializes an already allocated OFDate with the specified date and * time since now. * * \param seconds The seconds since now * \return An initialized OFDate with the specified date and time */ -- initWithTimeIntervalSinceNow: (int64_t)seconds; - -/** - * \brief Initializes an already allocated OFDate with the specified date and - * time since now. - * - * \param seconds The seconds since now - * \param microseconds The microsecond part of the time - * \return An initialized OFDate with the specified date and time - */ -- initWithTimeIntervalSinceNow: (int64_t)seconds - microseconds: (uint32_t)microseconds; +- initWithTimeIntervalSinceNow: (double)seconds; /** * \brief Initializes an already allocated OFDate with the specified string in * the specified format. * @@ -340,48 +296,30 @@ /** * \brief Returns the seconds since 1970-01-01T00:00:00Z. * * \return The seconds since 1970-01-01T00:00:00Z */ -- (int64_t)timeIntervalSince1970; - -/** - * \brief Returns the microseconds part of the seconds since - * 1970-01-01T00:00:00Z. - * - * \return The microseconds part of the seconds since 1970-01-01T00:00:00Z - */ -- (uint32_t)microsecondsOfTimeIntervalSince1970; +- (double)timeIntervalSince1970; /** * \brief Returns the seconds the receiver is after the date. * + * \param date Date date to generate the difference with receiver * \return The seconds the receiver is after the date. */ -- (int64_t)timeIntervalSinceDate: (OFDate*)otherDate; +- (double)timeIntervalSinceDate: (OFDate*)otherDate; /** - * \brief Returns the microseconds part of the seconds the receiver is after the - * date. + * \brief Returns the seconds the receiver is in the future. * - * \return The microseconds part of the seconds the receiver is after the date + * \return The seconds the receiver is in the future */ -- (uint32_t)microsecondsOfTimeIntervalSinceDate: (OFDate*)otherDate; +- (double)timeIntervalSinceNow; /** * \brief Creates a new date with the specified time interval added. * * \param seconds The seconds after the date * \return A new, autoreleased OFDate */ -- (OFDate*)dateByAddingTimeInterval: (int64_t)seconds; - -/** - * \brief Creates a new date with the specified time interval added. - * - * \param seconds The seconds after the date - * \param microseconds The microseconds after the date - * \return A new, autoreleased OFDate - */ -- (OFDate*)dateByAddingTimeInterval: (int64_t)seconds - withMicroseconds: (uint32_t)microseconds; +- (OFDate*)dateByAddingTimeInterval: (double)seconds; @end Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -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 Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -16,10 +16,12 @@ #include "config.h" #define __NO_EXT_QNX +#include + #ifndef _WIN32 # include # include #else # include @@ -191,33 +193,23 @@ #endif } + (void)sleepUntilDate: (OFDate*)date { - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFDate *now = [OFDate date]; - int64_t seconds; - uint32_t microseconds; - - if ((seconds = [date timeIntervalSinceDate: now]) < 0) - @throw [OFOutOfRangeException newWithClass: self]; - - microseconds = [date microsecondsOfTimeIntervalSinceDate: now]; - - [pool release]; + double seconds = [date timeIntervalSinceNow]; #ifndef _WIN32 if (seconds > UINT_MAX) @throw [OFOutOfRangeException newWithClass: self]; sleep((unsigned int)seconds); - usleep(microseconds); + usleep(nearbyint(remainder(seconds, 1) * 1000000)); #else - if (seconds * 1000 + microseconds / 1000 > UINT_MAX) + if (seconds * 1000 > UINT_MAX) @throw [OFOutOfRangeException newWithClass: self]; - Sleep(seconds * 1000 + microseconds / 1000); + Sleep(seconds * 1000); #endif } + (void)yield { Index: tests/OFDateTests.m ================================================================== --- tests/OFDateTests.m +++ tests/OFDateTests.m @@ -31,22 +31,20 @@ OFDate *d1, *d2; TEST(@"+[dateWithTimeIntervalSince1970:]", (d1 = [OFDate dateWithTimeIntervalSince1970: 0])) - TEST(@"+[dateWithTimeIntervalSince1970:microseconds:]", - (d2 = [d1 dateByAddingTimeInterval: 3600 * 25 + 5 - withMicroseconds: 1])) + TEST(@"-[dateByADdingTimeInterval:]", + (d2 = [d1 dateByAddingTimeInterval: 3600 * 25 + 5.000001])) TEST(@"-[description]", [[d1 description] isEqual: @"1970-01-01T00:00:00Z"] && [[d2 description] isEqual: @"1970-01-02T01:00:05Z"]) TEST(@"-[isEqual:]", [d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0]] && - ![d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0 - microseconds: 1]]) + ![d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0.0000001]]) TEST(@"-[compare:]", [d1 compare: d2] == OF_ORDERED_ASCENDING) TEST(@"-[second]", [d1 second] == 0 && [d2 second] == 5) Index: tests/OFSerializationTests.m ================================================================== --- tests/OFSerializationTests.m +++ tests/OFSerializationTests.m @@ -45,12 +45,11 @@ OFString *s; [a addObject: @"Qu\"xbar\ntest"]; [a addObject: [OFNumber numberWithInt: 1234]]; [a addObject: [OFMutableString stringWithString: @"asd"]]; - [a addObject: [OFDate dateWithTimeIntervalSince1970: 1234 - microseconds: 5678]]; + [a addObject: [OFDate dateWithTimeIntervalSince1970: 1234.5678]]; [d setObject: @"Hello" forKey: a]; [d setObject: @"B\"la" forKey: @"Blub"]; Index: tests/serialization.xml ================================================================== --- tests/serialization.xml +++ tests/serialization.xml @@ -1,33 +1,9 @@ - MDEyMzQ1Njc4OTo7PEFCQ0RFRkdISklLTE1OT1BRUlNUVVZXWFla - - - data - - - - Qu"xbar -test - 1234 - asd - - - - - Hello - - - Blub - - - B"la - - Hello Wo ld! How are you? https://webkeks.org/ @@ -89,7 +65,31 @@ list + + MDEyMzQ1Njc4OTo7PEFCQ0RFRkdISklLTE1OT1BRUlNUVVZXWFla + + + data + + + + Qu"xbar +test + 1234 + asd + 0x1.34a456d5cfaadp+10 + + + + Hello + + + Blub + + + B"la +