From: Craig A. Berry Date: Sat, 25 Apr 2009 22:51:38 +0000 (-0500) Subject: Make time64 use NV for time_t, I32 for year, not Quad_t. X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=d95a2ea538e6c332f36c34ca45b78d6ad93c3a1f;p=p5sagit%2Fp5-mst-13.2.git Make time64 use NV for time_t, I32 for year, not Quad_t. This means it should run on anything that does not have a 64-bit integer type available but does have a double. Presumably this includes platforms that define PERL_MICRO, so we now use the same extended time implementation for everything that runs Perl. --- diff --git a/pp_sys.c b/pp_sys.c index 0179323..bf362f0 100644 --- a/pp_sys.c +++ b/pp_sys.c @@ -29,10 +29,8 @@ #include "EXTERN.h" #define PERL_IN_PP_SYS_C #include "perl.h" -#if !defined(PERL_MICRO) && defined(Quad_t) -# include "time64.h" -# include "time64.c" -#endif +#include "time64.h" +#include "time64.c" #ifdef I_SHADOW /* Shadow password support for solaris - pdo@cs.umd.edu @@ -4469,15 +4467,9 @@ PP(pp_gmtime) { dVAR; dSP; -#if defined(PERL_MICRO) || !defined(Quad_t) - Time_t when; - const struct tm *err; - struct tm tmbuf; -#else Time64_T when; struct TM tmbuf; struct TM *err; -#endif const char *opname = PL_op->op_type == OP_LOCALTIME ? "localtime" : "gmtime"; static const char * const dayname[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; @@ -4485,30 +4477,12 @@ PP(pp_gmtime) {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -#if defined(PERL_MICRO) || !defined(Quad_t) - if (MAXARG < 1) - (void)time(&when); - else - when = (Time_t)SvIVx(POPs); - - if (PL_op->op_type == OP_LOCALTIME) - err = localtime(&when); - else - err = gmtime(&when); - - if (!err) - tmbuf = *err; -#else if (MAXARG < 1) { time_t now; (void)time(&now); when = (Time64_T)now; } else { - /* XXX POPq uses an SvIV so it won't work with 32 bit integer scalars - using a double causes an unfortunate loss of accuracy on high numbers. - What we really need is an SvQV. - */ double input = Perl_floor(POPn); when = (Time64_T)input; if (when != input && ckWARN(WARN_OVERFLOW)) { @@ -4521,7 +4495,6 @@ PP(pp_gmtime) err = S_localtime64_r(&when, &tmbuf); else err = S_gmtime64_r(&when, &tmbuf); -#endif if (err == NULL && ckWARN(WARN_OVERFLOW)) { /* XXX %lld broken for quads */ diff --git a/t/op/time.t b/t/op/time.t index 89ea04b..2ea1733 100644 --- a/t/op/time.t +++ b/t/op/time.t @@ -81,8 +81,9 @@ ok(gmtime() =~ /^(Sun|Mon|Tue|Wed|Thu|Fri|Sat)[ ] # Test gmtime over a range of times. { - # gm/localtime should go all the way from -2**63 to 2**63-1 - # but floating point hacks mean it gets unreliable for large numbers. + # The range should be limited only by the 53-bit mantissa of an IEEE double (or + # whatever kind of double you've got). Here we just prove that we're comfortably + # beyond the range possible with 32-bit time_t. my %tests = ( # time_t gmtime list scalar -2**35 => [52, 13, 20, 7, 2, -1019, 5, 65, 0, "Fri Mar 7 20:13:52 881"], diff --git a/time64.c b/time64.c index 764ac72..ca31acf 100755 --- a/time64.c +++ b/time64.c @@ -371,19 +371,19 @@ static struct TM *S_gmtime64_r (const Time64_T *in_time, struct TM *p) p->tm_zone = "UTC"; #endif - v_tm_sec = (int)(time % 60); - time /= 60; - v_tm_min = (int)(time % 60); - time /= 60; - v_tm_hour = (int)(time % 24); - time /= 24; - v_tm_tday = time; + v_tm_sec = (int)fmod(time, 60.0); + time = time >= 0 ? floor(time / 60.0) : ceil(time / 60.0); + v_tm_min = (int)fmod(time, 60.0); + time = time >= 0 ? floor(time / 60.0) : ceil(time / 60.0); + v_tm_hour = (int)fmod(time, 24.0); + time = time >= 0 ? floor(time / 24.0) : ceil(time / 24.0); + v_tm_tday = (int)time; WRAP (v_tm_sec, v_tm_min, 60); WRAP (v_tm_min, v_tm_hour, 60); WRAP (v_tm_hour, v_tm_tday, 24); - v_tm_wday = (int)((v_tm_tday + 4) % 7); + v_tm_wday = (int)fmod((v_tm_tday + 4.0), 7.0); if (v_tm_wday < 0) v_tm_wday += 7; m = v_tm_tday; @@ -395,7 +395,7 @@ static struct TM *S_gmtime64_r (const Time64_T *in_time, struct TM *p) if (m >= 0) { /* Gregorian cycles, this is huge optimization for distant times */ - cycles = (int)(m / (Time64_T) days_in_gregorian_cycle); + cycles = (int)floor(m / (Time64_T) days_in_gregorian_cycle); if( cycles ) { m -= (cycles * (Time64_T) days_in_gregorian_cycle); year += (cycles * years_in_gregorian_cycle); @@ -419,7 +419,7 @@ static struct TM *S_gmtime64_r (const Time64_T *in_time, struct TM *p) year--; /* Gregorian cycles */ - cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1); + cycles = (int)ceil((m / (Time64_T) days_in_gregorian_cycle) + 1); if( cycles ) { m -= (cycles * (Time64_T) days_in_gregorian_cycle); year += (cycles * years_in_gregorian_cycle); diff --git a/time64.h b/time64.h index 000f101..07bb33f 100644 --- a/time64.h +++ b/time64.h @@ -8,7 +8,7 @@ /* Set our custom types */ typedef INT_64_T Int64; typedef Int64 Time64_T; -typedef Int64 Year; +typedef I32 Year; /* A copy of the tm struct but with a 64 bit year */ diff --git a/time64_config.h b/time64_config.h index 6a1cd9d..42cc12c 100644 --- a/time64_config.h +++ b/time64_config.h @@ -15,10 +15,10 @@ /* INT_64_T - A 64 bit integer type to use to store time and others. + A numeric type to store time and others. Must be defined. */ -#define INT_64_T Quad_t +#define INT_64_T NV /* USE_TM64 @@ -77,9 +77,9 @@ can handle. We will use your system functions if the time falls inside these ranges. */ -#define SYSTEM_LOCALTIME_MAX CAT2(LOCALTIME_MAX,UL) -#define SYSTEM_LOCALTIME_MIN CAT2(LOCALTIME_MIN,UL) -#define SYSTEM_GMTIME_MAX CAT2(GMTIME_MAX,UL) -#define SYSTEM_GMTIME_MIN CAT2(GMTIME_MIN,UL) +#define SYSTEM_LOCALTIME_MAX CAT2(LOCALTIME_MAX,.0) +#define SYSTEM_LOCALTIME_MIN CAT2(LOCALTIME_MIN,.0) +#define SYSTEM_GMTIME_MAX CAT2(GMTIME_MAX,.0) +#define SYSTEM_GMTIME_MIN CAT2(GMTIME_MIN,.0) #endif /* TIME64_CONFIG_H */