Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.85k stars 523 forks source link

Bug in Time::localtime? #6183

Closed p5pRT closed 21 years ago

p5pRT commented 21 years ago

Migrated from rt.perl.org#19393 (status was 'resolved')

Searchable as RT19393$

p5pRT commented 21 years ago

From j.pritchard@eso.org

This is a bug report for perl from j.pritchard@​eso.org\, generated with the help of perlbug 1.34 running under perl v5.8.0.


The following script​:

\<--Start--> #! /usr/bin/perl

use Time​::Local; use Time​::gmtime; use Time​::localtime;

my $dateda=timelocal(0\,0\,0\,12\,9\,2002); printf("timelocal(0\,0\,0\,12\,9\,2002) ==> %04d-%02d-%02d\n"\,(localtime($dateda)->year()+1900)\,(localtime($dateda)->mon())\,localtime($dateda)->mday() ); $dateda=timelocal(0\,0\,0\,13\,9\,2002); printf("timelocal(0\,0\,0\,13\,9\,2002) ==> %04d-%02d-%02d\n"\,(localtime($dateda)->year()+1900)\,(localtime($dateda)->mon())\,localtime($dateda)->mday() ); $dateda=timelocal(0\,0\,0\,14\,9\,2002); printf("timelocal(0\,0\,0\,14\,9\,2002) ==> %04d-%02d-%02d\n"\,(localtime($dateda)->year()+1900)\,(localtime($dateda)->mon())\,localtime($dateda)->mday() );

\<--End-->

produces the following output...

timelocal(0\,0\,0\,12\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,13\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,14\,9\,2002) ==> 2002-09-14

Am I doing something wrong or is there a problem here?

Thanks in advance... John Pritchard



Flags​:   category=core   severity=low


Site configuration information for perl v5.8.0​:

Configured by bhcompile at Sun Sep 1 23​:55​:07 EDT 2002.

Summary of my perl5 (revision 5.0 version 8 subversion 0) configuration​:   Platform​:   osname=linux\, osvers=2.4.18-11smp\, archname=i386-linux-thread-multi   uname='linux daffy.perf.redhat.com 2.4.18-11smp #1 smp thu aug 15 06​:41​:59 edt 2002 i686 i686 i386 gnulinux '   config_args='-des -Doptimize=-O2 -march=i386 -mcpu=i686 -Dmyhostname=localhost -Dperladmin=root@​localhost -Dcc=gcc -Dcf_by=Red Hat\, Inc. -Dinstallprefix=/usr -Dprefix=/usr -Darchname=i386-linux -Dvendorprefix=/usr -Dsiteprefix=/usr -Duseshrplib -Dusethreads -Duseithreads -Duselargefiles -Dd_dosuid -Dd_semctl_semun -Di_db -Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr'   hint=recommended\, useposix=true\, d_sigaction=define   usethreads=define use5005threads=undef useithreads=define usemultiplicity=define   useperlio=define d_sfio=undef uselargefiles=define usesocks=undef   use64bitint=undef use64bitall=undef uselongdouble=undef   usemymalloc=n\, bincompat5005=undef   Compiler​:   cc='gcc'\, ccflags ='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm'\,   optimize='-O2 -march=i386 -mcpu=i686'\,   cppflags='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -I/usr/include/gdbm'   ccversion=''\, gccversion='3.2 20020822 (Red Hat Linux Rawhide 3.2-5)'\, gccosandvers=''   intsize=4\, longsize=4\, ptrsize=4\, doublesize=8\, byteorder=1234   d_longlong=define\, longlongsize=8\, d_longdbl=define\, longdblsize=12   ivtype='long'\, ivsize=4\, nvtype='double'\, nvsize=8\, Off_t='off_t'\, lseeksize=8   alignbytes=4\, prototype=define   Linker and Libraries​:   ld='gcc'\, ldflags =' -L/usr/local/lib'   libpth=/usr/local/lib /lib /usr/lib   libs=-lnsl -lgdbm -ldb -ldl -lm -lpthread -lc -lcrypt -lutil   perllibs=-lnsl -ldl -lm -lpthread -lc -lcrypt -lutil   libc=/lib/libc-2.2.92.so\, so=so\, useshrplib=true\, libperl=libperl.so   gnulibc_version='2.2.92'   Dynamic Linking​:   dlsrc=dl_dlopen.xs\, dlext=so\, d_dlsymun=undef\, ccdlflags='-rdynamic -Wl\,-rpath\,/usr/lib/perl5/5.8.0/i386-linux-thread-multi/CORE'   cccdlflags='-fpic'\, lddlflags='-shared -L/usr/local/lib'

Locally applied patches​:  


@​INC for perl v5.8.0​:   /usr/lib/perl5/5.8.0/i386-linux-thread-multi   /usr/lib/perl5/5.8.0   /usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi   /usr/lib/perl5/site_perl/5.8.0   /usr/lib/perl5/site_perl/5.6.1   /usr/lib/perl5/site_perl   /usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi   /usr/lib/perl5/vendor_perl/5.8.0   /usr/lib/perl5/vendor_perl/5.6.1   /usr/lib/perl5/vendor_perl   .


Environment for perl v5.8.0​:   HOME=/home/jpritcha   LANG=en_NZ   LANGUAGE (unset)   LD_LIBRARY_PATH=/midas/02FEB/lib​:/midas/98NOV/lib​:/usr/local/astro/Linux-ix86/star/share​:/usr/local/astro/Linux-ix86/star/share​:/usr/local/astro/Linux-ix86/star/share​:/usr/local/astro/Linux-ix86/star/share​:/usr/local/astro/Linux-ix86/star/share   LOGDIR (unset)   PATH=/astro/jdp/bin​:/home/jpritcha/bin/Linux-ix86​:/home/jpritcha/bin​:/usr/local/bin​:/usr/local/astro/Linux-ix86/bin​:/usr/local/astro/common/scripts​:/usr/local/astro/eb/bin/Linux-ix86​:/usr/local/astro/eb/bin​:/midas/02FEB/contrib/exec​:/midas/02FEB/gui/exec​:/sbin​:/usr/sbin​:/usr/local/astro/Linux-ix86/p2pp/bin​:/usr/bin​:/bin​:/usr/X11R6/bin​:.​:/usr/local/astro/Linux-ix86/star/bin​:/usr/local/astro/Linux-ix86/autoCd/autoCd   PERL_BADLANG (unset)   SHELL=/bin/tcsh

p5pRT commented 21 years ago

From @andk

On 24 Dec 2002 03​:13​:40 -0000\, "j.pritchard@​eso.org (via RT)" \perlbug\-followup@&#8203;perl\.org said​:

  > # New Ticket Created by j.pritchard@​eso.org   > # Please include the string​: [perl #19393]   > # in the subject line of all future correspondence about this issue.   > # \<URL​: http​://rt.perl.org/rt2/Ticket/Display.html?id=19393 >

  > This is a bug report for perl from j.pritchard@​eso.org\,   > generated with the help of perlbug 1.34 running under perl v5.8.0.

  > -----------------------------------------------------------------   > The following script​:

  > \<--Start-->   > #! /usr/bin/perl

  > use Time​::Local;   > use Time​::gmtime;   > use Time​::localtime;

  > my $dateda=timelocal(0\,0\,0\,12\,9\,2002);   > printf("timelocal(0\,0\,0\,12\,9\,2002) ==> %04d-%02d-%02d\n"\,(localtime($dateda)->year()+1900)\,(localtime($dateda)->mon())\,localtime($dateda)->mday() );   > $dateda=timelocal(0\,0\,0\,13\,9\,2002);   > printf("timelocal(0\,0\,0\,13\,9\,2002) ==> %04d-%02d-%02d\n"\,(localtime($dateda)->year()+1900)\,(localtime($dateda)->mon())\,localtime($dateda)->mday() );   > $dateda=timelocal(0\,0\,0\,14\,9\,2002);   > printf("timelocal(0\,0\,0\,14\,9\,2002) ==> %04d-%02d-%02d\n"\,(localtime($dateda)->year()+1900)\,(localtime($dateda)->mon())\,localtime($dateda)->mday() );

  > \<--End-->

  > produces the following output...

  > timelocal(0\,0\,0\,12\,9\,2002) ==> 2002-09-12   > timelocal(0\,0\,0\,13\,9\,2002) ==> 2002-09-12   > timelocal(0\,0\,0\,14\,9\,2002) ==> 2002-09-14

FWIW\, I cannot reproduce this here\, I get

timelocal(0\,0\,0\,12\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,13\,9\,2002) ==> 2002-09-13 timelocal(0\,0\,0\,14\,9\,2002) ==> 2002-09-14

Maybe it's time-zone or daylight-saving-time dependent?

-- andreas

p5pRT commented 21 years ago

From j.pritchard@eso.org

"Andreas Koenig (via RT)" wrote​:

Maybe it's time-zone or daylight-saving-time dependent?

Seems you are right...

encue​: ~/tmp> setenv TZ Chile/Continental encue​: ~/tmp> date Thu Dec 26 17​:18​:53 CLST 2002 encue​: ~/tmp> dtest2.pl timelocal(0\,0\,0\,12\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,13\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,14\,9\,2002) ==> 2002-09-14 encue​: ~/tmp> setenv TZ UTC encue​: ~/tmp> date Thu Dec 26 20​:20​:14 UTC 2002 encue​: ~/tmp> dtest2.pl timelocal(0\,0\,0\,12\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,13\,9\,2002) ==> 2002-09-13 timelocal(0\,0\,0\,14\,9\,2002) ==> 2002-09-14

So does this make it a bug or a feature???

John

-- + -- John Pritchard (2p2 Team\, La Silla Observatory)   +E S+ European Southern Observatory   O Alonso de Cordova 3107\, Vitacura\, Santiago 19-Chile   Off​: +56 2 463 3093 fx​: +56 2 463 3001   mailto​:j.pritchard@​eso.org -- + -- http​://www.sc.eso.org/~jpritcha

p5pRT commented 21 years ago

From @iabyn

On Thu\, Dec 26\, 2002 at 05​:21​:14PM -0300\, John Pritchard wrote​:

"Andreas Koenig (via RT)" wrote​:

Maybe it's time-zone or daylight-saving-time dependent?

Seems you are right...

encue​: ~/tmp> setenv TZ Chile/Continental encue​: ~/tmp> date Thu Dec 26 17​:18​:53 CLST 2002 encue​: ~/tmp> dtest2.pl timelocal(0\,0\,0\,12\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,13\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,14\,9\,2002) ==> 2002-09-14 encue​: ~/tmp> setenv TZ UTC encue​: ~/tmp> date Thu Dec 26 20​:20​:14 UTC 2002 encue​: ~/tmp> dtest2.pl timelocal(0\,0\,0\,12\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,13\,9\,2002) ==> 2002-09-13 timelocal(0\,0\,0\,14\,9\,2002) ==> 2002-09-14

So does this make it a bug or a feature???

It's just the transition to DST - there are two hours that map to the same internal time\, so Not-A-Bug. ie at 00​:00\, the clocks go back to 23​:00.

The following script​:

  use Time​::Local;   use Time​::gmtime;   use Time​::localtime;

  for my $day (12..13) {   for my $hour ('00'..'23') {   my $dateda=timelocal(0\,0\,$hour\,$day\,9\,2002);   printf("timelocal(0\,0\,$hour\,$day\,9\,2002) ==> "   . " %10d %04d-%02d-%02d %02d​:%02d​:%02d dst=%d\n"\,   $dateda\,   localtime($dateda)->year()+1900\,   localtime($dateda)->mon()\,   localtime($dateda)->mday()\,   localtime($dateda)->hour()\,   localtime($dateda)->min()\,   localtime($dateda)->sec()\,   localtime($dateda)->isdst()\,   );   }   }

outputs​:

[davem@​percy davem]$ TZ=Chile/Continental perl5.8.0 /tmp/p [snip] timelocal(0\,0\,22\,12\,9\,2002) ==> 1034474400 2002-09-12 22​:00​:00 dst=0 timelocal(0\,0\,23\,12\,9\,2002) ==> 1034478000 2002-09-12 23​:00​:00 dst=0 timelocal(0\,0\,00\,13\,9\,2002) ==> 1034478000 2002-09-12 23​:00​:00 dst=0 timelocal(0\,0\,01\,13\,9\,2002) ==> 1034481600 2002-09-13 01​:00​:00 dst=1 timelocal(0\,0\,02\,13\,9\,2002) ==> 1034485200 2002-09-13 02​:00​:00 dst=1 timelocal(0\,0\,03\,13\,9\,2002) ==> 1034488800 2002-09-13 03​:00​:00 dst=1 ...

-- "Emacs isn't a bad OS once you get used to it. It just lacks a decent editor."

p5pRT commented 21 years ago

From j.pritchard@eso.org

"Dave Mitchell (via RT)" wrote​:

It's just the transition to DST - there are two hours that map to the same internal time\, so Not-A-Bug. ie at 00​:00\, the clocks go back to 23​:00.

Ahhhh\, many thanks for the clarification and solution.

Best regards John

-- + -- John Pritchard (Science Operations\, La Silla Observatory)   +E S+ European Southern Observatory   O Alonso de Cordova 3107\, Vitacura\, Santiago 19-Chile   Off​: +56 2 463 3093 fx​: +56 2 463 3001   mailto​:j.pritchard@​eso.org -- + -- http​://www.sc.eso.org/~jpritcha

p5pRT commented 21 years ago

From @jhi

I'm marking the problem ticket as resolved.

p5pRT commented 21 years ago

@jhi - Status changed from 'new' to 'resolved'

p5pRT commented 21 years ago

From perl5-porters@ton.iguana.be

In article \20021227215004\.A28503@&#8203;\_dgroup\.com\,   Dave Mitchell \davem@&#8203;fdgroup\.com writes​:

timelocal(0\,0\,0\,12\,9\,2002) ==> 2002-09-12 timelocal(0\,0\,0\,13\,9\,2002) ==> 2002-09-13 timelocal(0\,0\,0\,14\,9\,2002) ==> 2002-09-14

So does this make it a bug or a feature???

It's just the transition to DST - there are two hours that map to the same internal time\, so Not-A-Bug. ie at 00​:00\, the clocks go back to 23​:00.

Well\, not exactly​:

TZ=Chile/Continental perl -wle 'print join" "\,localtime(1034477999)' 59 59 22 12 9 102 6 284 0 TZ=Chile/Continental perl -wle 'print join" "\,localtime(1034477999+2)' 1 0 23 12 9 102 6 284 0 TZ=Chile/Continental perl -wle 'print join" "\,localtime(1034477999+3600)' 59 59 23 12 9 102 6 284 0 TZ=Chile/Continental perl -wle 'print join" "\,localtime(1034477999+3601)' 0 0 1 13 9 102 0 285 1 TZ=Chile/Continental perl -wle 'print join" "\,localtime(1034477999+3602)' 1 0 1 13 9 102 0 285 1

So time actually skips 0​:00 to 1​:00\, and there is no 0​:00 really. Still\, if you want to put it anywhere\, it corresponds to 1034478000+3600=1034481600

So I'd call this a bug​: TZ=Chile/Continental perl -MTime​::Local -wle 'print timelocal(0\,0\,0\,13\,9\,2002)' 1034478000 TZ=Chile/Continental perl -MTime​::Local -wle 'print timelocal(0\,0\,0\,13\,9\,102)' 1034478000

It should be either an error or 1034481600

PS for the original poster​: Nobody puts the daylight saving jumps during the day\, so if you want to use timelocal/localtime for date manipulation\, set the hour to 12\, and use things like​: timelocal(0\,0\,12\,13\,9\,102)

p5pRT commented 21 years ago

From @iabyn

On Mon\, Dec 30\, 2002 at 09​:58​:51PM +0000\, Ton Hospel wrote​:

In article \20021227215004\.A28503@&#8203;\_dgroup\.com\, Dave Mitchell \davem@&#8203;fdgroup\.com writes​:

It's just the transition to DST - there are two hours that map to the same internal time\, so Not-A-Bug. ie at 00​:00\, the clocks go back to 23​:00.

Well\, not exactly​:

[ snip]

So time actually skips 0​:00 to 1​:00\, and there is no 0​:00 really. Still\, if you want to put it anywhere\, it corresponds to 1034478000+3600=1034481600

So I'd call this a bug​: TZ=Chile/Continental perl -MTime​::Local -wle 'print timelocal(0\,0\,0\,13\,9\,2002)' 1034478000 TZ=Chile/Continental perl -MTime​::Local -wle 'print timelocal(0\,0\,0\,13\,9\,102)' 1034478000

It should be either an error or 1034481600

D'oh - I got confused by Chile's clocks going fowards in the autumn\, whereas they go backwards in the UK and other places at that time :-(

So yes\, its a bug. Attached patch adjusts 'inbetween' dates to the DST-shifted equivalent.

-- "You're so sadly neglected\, and often ignored. A poor second to Belgium\, When going abroad." Monty Python - "Finland"

Inline Patch ```diff --- lib/Time/Local.pm- Wed Jan 1 21:24:34 2003 +++ lib/Time/Local.pm Wed Jan 1 22:29:54 2003 @@ -132,7 +132,18 @@ or return $loc_t; # Adjust for DST change - $loc_t + $dst_off; + $loc_t += $dst_off; + + # for a negative offset from GMT, and if the original date + # was a non-extent gap in a forward DST jump, we should + # now have the wrong answer - undo the DST adjust; + + return $loc_t if $zone_off <= 0; + + my ($s,$m,$h) = localtime($loc_t); + $loc_t -= $dst_off if $s != $_[0] || $m != $_[1] || $h != $_[2]; + + $loc_t; } --- lib/Time/Local.t- Wed Jan 1 21:24:45 2003 +++ lib/Time/Local.t Wed Jan 1 22:47:17 2003 @@ -28,7 +28,7 @@ # use vmsish 'time' makes for oddness around the Unix epoch if ($^O eq 'VMS') { $time[0][2]++ } -print "1..", @time * 2 + 5, "\n"; +print "1..", @time * 2 + 6, "\n"; $count = 1; for (@time) { @@ -93,6 +93,20 @@ or print "not "; print "ok ", $count++, "\n"; +# bugid #19393 +# At a DST transition, the clock skips forward, eg from 01:59:59 to +# 03:00:00. In this case, 02:00:00 is an invalid time, and should be +# treated like 03:00:00 rather than 01:00:00 - negative zone offsets used +# to do the latter + +{ + my $hour = (localtime(timelocal(0, 0, 2, 7, 3, 102)))[2]; + # testers in US/Pacific should get 3, + # other testers should get 2 + print "not " unless $hour == 2 || $hour == 3; + print "ok ", $main::count++, "\n"; +} + #print "Testing timelocal.pl module too...\n"; package test; ```
p5pRT commented 21 years ago

From @jhi

I think bug found\, and patched\, so I'm marking the problem ticket as resolved.

p5pRT commented 21 years ago

@jhi - Status changed from 'open' to 'resolved'

p5pRT commented 21 years ago

From @rgs

Dave Mitchell wrote​:

Attached patch adjusts 'inbetween' dates to the DST-shifted equivalent.

Thanks\, applied as #18497.

p5pRT commented 21 years ago

From @iabyn

closing (for 3rd time)\, since bug is fixed

p5pRT commented 21 years ago

@iabyn - Status changed from 'open' to 'resolved'