summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig A. Berry <craigberry@mac.com>2009-04-25 17:51:38 -0500
committerCraig A. Berry <craigberry@mac.com>2009-04-25 18:11:55 -0500
commitd95a2ea538e6c332f36c34ca45b78d6ad93c3a1f (patch)
tree7af896a0f675ba7495ed49cb5f70ad4a26e60d65
parent4efe685a06ca02d3bdef0d82787eb46835ec9e7e (diff)
downloadperl-d95a2ea538e6c332f36c34ca45b78d6ad93c3a1f.tar.gz
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.
-rw-r--r--pp_sys.c31
-rw-r--r--t/op/time.t5
-rwxr-xr-xtime64.c20
-rw-r--r--time64.h2
-rw-r--r--time64_config.h12
5 files changed, 22 insertions, 48 deletions
diff --git a/pp_sys.c b/pp_sys.c
index 01793236db..bf362f06fe 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 89ea04baae..2ea173307e 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 764ac721b0..ca31acf0ad 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 000f1018cb..07bb33fd84 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 6a1cd9d063..42cc12c88e 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 */