/* * Copyright (c) 2008 - 2010 * Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE included in * the packaging of this file. */ #include "config.h" #include #include #import "OFDate.h" #import "OFString.h" #import "OFAutoreleasePool.h" #import "OFExceptions.h" #if !defined(HAVE_GMTIME_R) && defined(OF_THREADS) # import "OFThread.h" static OFMutex *mutex; #endif #ifdef HAVE_GMTIME_R # define GMTIME_RET(field) \ struct tm tm; \ \ if (gmtime_r(&sec, &tm) == NULL) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ return tm.field; #else # ifdef OF_THREADS # define GMTIME_RET(field) \ struct tm *tm; \ \ [mutex lock]; \ \ @try { \ if ((tm = gmtime(&sec)) == NULL) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ return tm->field; \ } @finally { \ [mutex unlock]; \ } # else # define GMTIME_RET(field) \ struct tm *tm; \ \ if ((tm = gmtime(&sec)) == NULL) \ @throw [OFOutOfRangeException newWithClass: isa]; \ \ return tm->field; # endif #endif @implementation OFDate #if !defined(HAVE_GMTIME_R) && defined(OF_THREADS) + (void)initialize { if (self == [OFDate class]) mutex = [[OFMutex alloc] init]; } #endif + date { return [[[self alloc] init] autorelease]; } + dateWithTimeIntervalSince1970: (time_t)sec { return [[[self alloc] initWithTimeIntervalSince1970: sec] autorelease]; } + dateWithTimeIntervalSince1970: (time_t)sec microseconds: (suseconds_t)usec { return [[[self alloc] initWithTimeIntervalSince1970: sec microseconds: usec] 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: t.tv_usec]; } - initWithTimeIntervalSince1970: (time_t)sec_ { return [self initWithTimeIntervalSince1970: sec_ microseconds: 0]; } - initWithTimeIntervalSince1970: (time_t)sec_ microseconds: (suseconds_t)usec_ { self = [super init]; sec = sec_; usec = usec_; return self; } - (BOOL)isEqual: (id)obj { if (![obj isKindOfClass: [OFDate class]]) return NO; if (((OFDate*)obj)->sec != sec || ((OFDate*)obj)->usec != usec) return NO; return YES; } - copy { return [self retain]; } - (of_comparison_result_t)compare: (id)obj { if (![obj isKindOfClass: [OFDate class]]) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; if (sec < ((OFDate*)obj)->sec) return OF_ORDERED_ASCENDING; if (sec > ((OFDate*)obj)->sec) return OF_ORDERED_DESCENDING; if (usec < ((OFDate*)obj)->usec) return OF_ORDERED_ASCENDING; if (usec > ((OFDate*)obj)->usec) return OF_ORDERED_DESCENDING; return OF_ORDERED_SAME; } - (OFString*)description { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFString *tmp, *ret; tmp = [self stringWithFormat: @"%Y-%m-%dT%H:%M:%S"]; if (usec == 0) ret = [OFString stringWithFormat: @"%sZ", [tmp cString]]; else ret = [OFString stringWithFormat: @"%s.%06dZ", [tmp cString], usec]; [ret retain]; [pool release]; return [ret autorelease]; } - (int)seconds { GMTIME_RET(tm_sec) } - (suseconds_t)microseconds { return usec; } - (int)minutes { GMTIME_RET(tm_min) } - (int)hours { GMTIME_RET(tm_hour) } - (int)dayOfMonth { GMTIME_RET(tm_mday) } - (int)monthOfYear { GMTIME_RET(tm_mon + 1) } - (int)year { GMTIME_RET(tm_year + 1900) } - (int)dayOfWeek { GMTIME_RET(tm_wday) } - (int)dayOfYear { GMTIME_RET(tm_yday + 1) } - (OFString*)stringWithFormat: (OFString*)fmt { struct tm tm; char *buf; #ifdef HAVE_GMTIME_R if (gmtime_r(&sec, &tm) == NULL) @throw [OFOutOfRangeException newWithClass: isa]; #else # ifdef OF_THREADS [mutex lock]; @try { # endif struct tm *tmp; if ((tmp = gmtime(&sec)) == NULL) @throw [OFOutOfRangeException newWithClass: isa]; tm = *tmp; # ifdef OF_THREADS } @finally { [mutex unlock]; } # endif #endif buf = [self allocMemoryWithSize: of_pagesize]; @try { if (!strftime(buf, of_pagesize, [fmt cString], &tm)) @throw [OFOutOfRangeException newWithClass: isa]; return [OFString stringWithCString: buf]; } @finally { [self freeMemory: buf]; } } @end