http://qs321.pair.com?node_id=1209514


in reply to Date::Parse - how to correctly parse dates between 1901 and 1969

The 100 years oddity would seem to be related to issue #105031 for Date::Parse:
After str2time uses strptime to break up the incoming date, it passes the result (with $year - 1900) to Time::Local::timelocal. timelocal uses a sliding window to determine if the year should be 19xx or 20xx, completely throwing away the *known* four-digit year that we sent to str2time.
Time::Local interprets the (two digit) date like this:
Years in the range 0..99 are interpreted as shorthand for years in the rolling "current century," defined as 50 years on either side of the current year. Thus, today, in 1999, 0 would refer to 2000, and 45 to 2045, but 55 would refer to 1955. Twenty years from now, 55 would instead refer to 2055. This is messy, but matches the way people currently think about two digit dates.
Years 1968 and 1969 mark the crossover of that window - i.e. 1968 is on one side of 2018 (50 years), and 1969 is on the other (49 years)...
my @dates = ( "1901-01-01 00:00:00", "1968-12-31 23:59:59", "1969-01-01 00:00:00", "1969-12-31 23:59:59", "1970-01-01 00:00:01", ); for my $string (@dates) { my $epoch = str2time( $string, 'GMT' ); print "$string ($epoch seconds)\n"; my $date = DateTime->from_epoch( epoch => $epoch ); print $date->ymd, " ", $date->hms, "\n\n"; }
OUTPUT:
1901-01-01 00:00:00 (978307200 seconds) 2001-01-01 00:00:00 1968-12-31 23:59:59 (3124223999 seconds) 2068-12-31 23:59:59 1969-01-01 00:00:00 (-31536000 seconds) 1969-01-01 00:00:00 1969-12-31 23:59:59 (-1 seconds) 1969-12-31 23:59:59 1970-01-01 00:00:01 (1 seconds) 1970-01-01 00:00:01
 
To verify that the problem is with Date::Parse you can use Time::Local directly to show it returns the correct results if you give it the 4 digit year:
use Time::Local; my %hash = ( "1901-01-01 00:00:00" => [00,00,00,01,00,1901], "1968-12-31 23:59:59" => [59,59,23,31,11,1968], "1969-01-01 00:00:00" => [00,00,00,01,00,1969], "1969-12-31 23:59:59" => [59,59,23,31,11,1969], "1970-01-01 00:00:01" => [01,00,00,01,00,1970], ); for my $string (@dates) { my $array = $hash{$string}; my $epoch = timegm( @$array ); print "$string ($epoch seconds)\n"; my $date = DateTime->from_epoch( epoch => $epoch ); print $date->ymd, " ", $date->hms, "\n\n"; }
OUTPUT:
1901-01-01 00:00:00 (-2177452800 seconds) 1901-01-01 00:00:00 1968-12-31 23:59:59 (-31536001 seconds) 1968-12-31 23:59:59 1969-01-01 00:00:00 (-31536000 seconds) 1969-01-01 00:00:00 1969-12-31 23:59:59 (-1 seconds) 1969-12-31 23:59:59 1970-01-01 00:00:01 (1 seconds) 1970-01-01 00:00:01

Replies are listed 'Best First'.
Re^2: Date::Parse - how to correctly parse dates between 1901 and 1969
by eniad (Acolyte) on Feb 20, 2018 at 00:01 UTC
    This explains my difficulty. Thank you. Now that I understand where the `$year - 1900` is happening, I can figure out how to reliably parse then format the input date. I will post my updated code.