This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
gmtime/localtime are busted around 2**48
authorMichael G Schwern <schwern@pobox.com>
Sun, 31 Jan 2010 10:53:43 +0000 (02:53 -0800)
committerH.Merijn Brand <h.m.brand@xs4all.nl>
Sun, 31 Jan 2010 11:46:14 +0000 (12:46 +0100)
Michael G Schwern wrote:
> Anyhow, I'm willing to let that drop, but I want figure out A) why its
> failing so early because it might be masking a bug, this is not
> predicted behavior, and most importantly B) to get it to error, or at
> least warn.
>
> I know B is possible, I did it for Time::y2038.  I'll figure that part
> out and try to dig into A.  I would like to call B a blocker for 5.12.

Found the bug, patch attached.

v_tm_tday is an NV, so casting time to an integer will cause an overflow
2**31 days after 1970 or somewhere between 2**47 and 2**48.  Not sure why the
compiler didn't warn about that.

This makes it work until the year overflows.

As for putting in a warning, there's two options:
1) A few days before the 32 bit year overflows.
2) At some reasonable point before there's too much floating point inaccuracy.

The possibility of long doubles will make #2 difficult to nail down, but I'll
be happy with +/- 2**53.

--
24. Must not tell any officer that I am smarter than they are, especially
     if it's true.
     -- The 213 Things Skippy Is No Longer Allowed To Do In The U.S. Army
            http://skippyslist.com/list/

From 9e940e610ac5b2fbb09a554f505963094a4a0745 Mon Sep 17 00:00:00 2001
From: Michael G. Schwern <schwern@pobox.com>
Date: Sun, 31 Jan 2010 02:24:50 -0800
Subject: [PATCH] Type conversion bug in gmtime64 that was causing it to crap out around 2**48

Signed-off-by: H.Merijn Brand <h.m.brand@xs4all.nl>
time64.c

index ca31acf..1d43f39 100644 (file)
--- a/time64.c
+++ b/time64.c
@@ -377,7 +377,7 @@ static struct TM *S_gmtime64_r (const Time64_T *in_time, struct TM *p)
     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;
+    v_tm_tday = time;
 
     WRAP (v_tm_sec, v_tm_min, 60);
     WRAP (v_tm_min, v_tm_hour, 60);