atoomic / perl-TimeDate

time & date parsing and formatting perl library
http://search.cpan.org/dist/TimeDate/
1 stars 4 forks source link

Date:Parse mangling 4-digit year dates [rt.cpan.org #53413] #25

Open atoomic opened 4 years ago

atoomic commented 4 years ago

Migrated from rt.cpan.org#53413 (status was 'open')

Requestors:

Attachments:

From stephen@enterity.com on 2010-01-05 21:37:05 :

strptime subtracts 1900 from 4 digit dates. My problem arose from trying to set
a date with a year of 1924 kept coming out as 2024. When I removed this line
the problem goes away. I think it's because 2-digit years are treated on a
rolling basis under timelocal.

This is in version 2.27 of Date::Parse, but appears to remain present in 2.30

From gbarr@pobox.com on 2010-01-06 00:55:34 :

strptime returns year as an offset from 1900, just as localtime does

perl -Ilib -MDate::Parse -le '$,=" "; my $t = localtime(time); print $t; print localtime(time); print strptime($t);'
Tue Jan  5 18:53:26 2010
26 53 18 5 0 110 2 4 0
26 53 18 5 0 110 

this is not a bug

Graham.

From mbethke@cpan.org on 2016-05-16 04:22:33 :

Looks like this ticket could be closed, right? Just so as not to have people like me getting shocked at seeing 6yo "Important" bugs still open :)

From fullermd@cpan.org on 2016-12-26 00:05:03 :

> this is not a bug

I'm pretty sure it is, since str2time() internally uses strptime(), which means it currently fails badly on dates 1966 and before.

This is also the meat of bug 84075, bug 105031

From jim.avera@gmail.com on 2018-12-29 22:12:59 :

On Tue Jan 05 19:55:34 2010, gbarr@pobox.com wrote:
> strptime returns year as an offset from 1900, just as localtime does
...
> this is not a bug

Hi Graham,

The bug is not in strptime(), but in str2time(), where it calls Time::Local::timegm (or timelocal), passing the year returned by strptime without compensating for Time::Local's non-standard fiddling of 2-digit years.

Time::Local::timegm will change a 2-digit year to simulate human behavior, which is wrong in this case.  You need to ALWAYS pass a 4-digit year to Time::Local::timegm (or timelocal) to prevent mis-behavior.   In your case, I think that means adding 1900 to the year returned by strptime().

Cheers.

From jim.avera@gmail.com on 2018-12-29 22:22:58 :

Attached is a patch which fixes this bug.  Graham, would you please review it?

Thanks very much.

From jim.avera@gmail.com on 2018-12-29 22:26:25 :

Ignore that, something horrible filled the patch file with binary junk... I'll attach a good patch momentarily (sorry!)

From jim.avera@gmail.com on 2018-12-29 22:36:20 :

Ok, here is a good patch (attached).  The previous one was messed up because a vim temporary file was present in the new hierarchy.

I'll also attach a demo script which shows the bug.

From jim.avera@gmail.com on 2018-12-29 22:37:06 :

diff -Naur /usr/share/perl5/Date/Parse.pm /tmp/new/Date/Parse.pm
--- /usr/share/perl5/Date/Parse.pm  2014-04-26 01:05:35.000000000 -0700
+++ /tmp/new/Date/Parse.pm  2018-12-29 14:27:26.030661550 -0800
@@ -261,7 +261,8 @@
  if (defined $zone) {
    $result = eval {
      local $SIG{__DIE__} = sub {}; # Ick!
-     timegm($ss,$mm,$hh,$day,$month,$year);
+     # Prevent Time::Local::timegm fiddling with certain 2-digit years
+     timegm($ss,$mm,$hh,$day,$month,1900+$year);
    };
    return undef
      if !defined $result
@@ -273,7 +274,8 @@
  else {
    $result = eval {
      local $SIG{__DIE__} = sub {}; # Ick!
-     timelocal($ss,$mm,$hh,$day,$month,$year);
+     # Prevent Time::Local::timelocal fiddling with certain 2-digit years
+     timelocal($ss,$mm,$hh,$day,$month,1900+$year);
    };
    return undef
      if !defined $result

From jim.avera@gmail.com on 2018-12-30 02:03:13 :

Ok, that patch did not handle years down to 1901.  Attached is a new patch, and a proper test script.

Currently strptime() does not actually return year-1900 for dates prior to January 1, 1901.  I'm guessing this is because some code somewhere can not handle zero or negative "year" values (i.e. -1 for the year 1899). 

The new patch has to take that into account, and the corresponding test cases are "skipped".

Best,
-Jim