From: Michael G Schwern Date: Sat, 13 Sep 2008 11:26:47 +0000 (-0700) Subject: Update from the latest y2038. X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=a64acb403ac07729c7cd29947ba931e324d56829;p=p5sagit%2Fp5-mst-13.2.git Update from the latest y2038. Include the ability to use the system functions. This speeds up localtime() several times when the time is < 32 bits. Don't bother using the system gmtime() as it will probably just have bugs. We need to wait for config to give us LOCALTIME_MIN/MAX but I think assuming time_t is at least 32 bits is good enough for now. This restores the full performance of localtime() for < 32 bit numbers and gmtime() is now only 10% slower. --- diff --git a/localtime64.c b/localtime64.c index 80c0707..4e579a4 100644 --- a/localtime64.c +++ b/localtime64.c @@ -94,6 +94,10 @@ static const int dow_year_start[28] = { #define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0) #define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a)) +#define SHOULD_USE_SYSTEM_LOCALTIME(a) ( USE_SYSTEM_LOCALTIME && (a) <= SYSTEM_LOCALTIME_MAX ) +#define SHOULD_USE_SYSTEM_GMTIME(a) ( USE_SYSTEM_GMTIME && (a) <= SYSTEM_GMTIME_MAX ) + + int _is_exception_century(Int64 year) { int is_exception = ((year % 100 == 0) && !(year % 400 == 0)); @@ -144,6 +148,11 @@ time_t _my_timegm(struct tm *date) { } +#ifdef NDEBUG +#define CHECK_TM(a) +#else +#define CHECK_TM(a) _check_tm(a); + void _check_tm(struct tm *tm) { int is_leap = IS_LEAP(tm->tm_year); @@ -175,6 +184,8 @@ void _check_tm(struct tm *tm) assert(tm->tm_gmtoff <= 24 * 60 * 60); #endif } +#endif + /* The exceptional centuries without leap years cause the cycle to shift by 16 @@ -229,6 +240,14 @@ struct tm *gmtime64_r (const Time64_T *in_time, struct tm *p) Time64_T time = *in_time; Int64 year = 70; + /* Use the system gmtime() if time_t is small enough */ + if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) { + time_t safe_time = *in_time; + localtime_r(&safe_time, p); + CHECK_TM(p) + return p; + } + #ifdef HAS_TM_TM_GMTOFF p->tm_gmtoff = 0; #endif @@ -317,7 +336,7 @@ struct tm *gmtime64_r (const Time64_T *in_time, struct tm *p) p->tm_sec = v_tm_sec, p->tm_min = v_tm_min, p->tm_hour = v_tm_hour, p->tm_mon = v_tm_mon, p->tm_wday = v_tm_wday; - _check_tm(p); + CHECK_TM(p) return p; } @@ -330,6 +349,14 @@ struct tm *localtime64_r (const Time64_T *time, struct tm *local_tm) Int64 orig_year; int month_diff; + /* Use the system localtime() if time_t is small enough */ + if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) { + safe_time = *time; + localtime_r(&safe_time, local_tm); + CHECK_TM(local_tm) + return local_tm; + } + gmtime64_r(time, &gm_tm); orig_year = gm_tm.tm_year; @@ -365,7 +392,7 @@ struct tm *localtime64_r (const Time64_T *time, struct tm *local_tm) if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 ) local_tm->tm_yday--; - _check_tm(local_tm); + CHECK_TM(local_tm) return local_tm; } diff --git a/localtime64.h b/localtime64.h index b6c65fc..d676c28 100644 --- a/localtime64.h +++ b/localtime64.h @@ -14,7 +14,28 @@ HAS_TM_TM_ZONE Defined if your tm struct has a "tm_zone" element. + + SYSTEM_LOCALTIME_MAX + SYSTEM_LOCALTIME_MIN + SYSTEM_GMTIME_MAX + SYSTEM_GMTIME_MIN + Maximum and minimum values your system's gmtime() and localtime() + can handle. + + USE_SYSTEM_LOCALTIME + USE_SYSTEM_GMTIME + Should we use the system functions if the time is inside their range? */ +#define SYSTEM_LOCALTIME_MAX 2147483647 /* XXX Replace with LOCALTIME_MAX */ +#define SYSTEM_LOCALTIME_MIN -2147483648 /* XXX Replace with LOCALTIME_MIN */ +#define SYSTEM_GMTIME_MAX GMTIME_MAX +#define SYSTEM_GMTIME_MIN GMTIME_MIN + +/* It'll be faster */ +#define USE_SYSTEM_LOCALTIME 1 + +/* No point risking system bugs, ours works fine */ +#define USE_SYSTEM_GMTIME 0 /* 64 bit types. Set as appropriate for your system. */