FW: timelocal() discrepancy vs DateTime->epoch

[email protected] ("Lu Feng") Tue, 14 Mar 2017 21:11:41 -0400
Newsgroups perl.datetime
Message-ID <[email protected]>
I noticed that the UNIX time from timelocal() started to differ from that
you get from using DateTime module, for dates earlier than 11/6/1910.
 
For the America/New_York local timezone, timelocal() thinks there was a DST
switch on 11/6/1910, while DateTime module thinks there was none.
 
If you run the attached script (after setting your host TZ env to New York)
twice (with Perl 5.24), you will see these outputs:
 
F:\ABT\Dev\PerlUtil>perl David.pl 1910 11 06 08 00 00
Epoch for 19101106:080000 (UTC) =       -1866729600     based on Epoch().
Epoch for 19101106:080000 (UTC) =       -1866729600     based on timegm().
Epoch for 19101106:080000 (NYC) =       -1866711600     based on Epoch().
Epoch for 19101106:080000 (NYC) =       -1866711600     based on
timelocal().
 
F:\ABT\Dev\PerlUtil>perl David.pl 1910 11 05 08 00 00
Epoch for 19101105:080000 (UTC) =       -1866816000     based on Epoch().
Epoch for 19101105:080000 (UTC) =       -1866816000     based on timegm().
Epoch for 19101105:080000 (NYC) =       -1866798000     based on Epoch().
Epoch for 19101105:080000 (NYC) =       -1866801600     based on
timelocal().
 
So it seems either DateTime or timelocal() has a bug regarding the DST
switch over on 11/6/1910.  Am I missing something?
 
Regards,
Lu Feng
David.pl (application/octet-stream, 1.9 KB)
use strict;
use DateTime;
use Time::Local;

die "Usage: perl xEpoch.pl yr month dd hh minute ss\n" 
    unless @ARGV == 6;

my $yr = $ARGV[0];
my $month = $ARGV[1];
my $dd = $ARGV[2];
my $hh = $ARGV[3];
my $minute = $ARGV[4];
my $ss = $ARGV[5];

print "Epoch for $yr$month$dd:$hh$minute$ss (UTC) = \t",
    Epoch($yr, $month, $dd, $hh, $minute, $ss, 'UTC'), 
    "\tbased on Epoch().\n";

# timegm cannot handle an input that represents a legit leap second.
print "Epoch for $yr$month$dd:$hh$minute$ss (UTC) = \t",
    timegm($ss, $minute, $hh, $dd, $month-1, ($yr<1900?$yr-1900:$yr)), 
    "\tbased on timegm().\n";

print "Epoch for $yr$month$dd:$hh$minute$ss (NYC) = \t",
    Epoch($yr, $month, $dd, $hh, $minute, $ss, 'America/New_York'), 
    "\tbased on Epoch().\n";

# timelocal cannot handle an input that represents a legit leap second.
print "Epoch for $yr$month$dd:$hh$minute$ss (NYC) = \t",
    timelocal($ss, $minute, $hh, $dd, $month-1, ($yr<1900?$yr-1900:$yr)), 
    "\tbased on timelocal().\n";


sub Epoch {
    #Inputs:
    my $yyyy = $_[0];
    my $month = $_[1];
    my $dd = $_[2];
    my $hh = $_[3];
    my $minute = $_[4];
    my $ss = $_[5];
    my $tz = $_[6];

    my $epoch;
    eval { # Use error trapping in case an invalid timestamp is provided.
        my $dt = DateTime->new(
                               year        => $yyyy,
                               month       => $month,
                               day         => $dd,
                               hour        => $hh,
                               minute      => $minute,
                               second      => $ss,
                               time_zone   => $tz);
        $epoch = $dt->epoch;
    };
    if ($@) {                   # Report the error msg in $@.
        $epoch = "Err BaseCamp::Epoch: $yyyy:$month:$dd:$hh:$minute:$ss:$tz --> "
         . $@;
        print STDERR "$epoch\n";
    }
    return $epoch;
}