Perl 将历史时间戳从UTC转换为本地时间戳

Perl 将历史时间戳从UTC转换为本地时间戳,perl,utc,Perl,Utc,我有一个文件,上面有过去的时间戳,都是UTC格式的。我需要把这些转换成东部时间。我已经很接近了,但是夏令时的转换搞砸了 #!/usr/bin/perl use strict; use warnings; use Time::Piece; #DST not in effect my $utc = '2015-03-08 01:59:00.000'; my $local = utc_to_local($utc); print "DST not in effect: utc($utc) = loca

我有一个文件,上面有过去的时间戳,都是UTC格式的。我需要把这些转换成东部时间。我已经很接近了,但是夏令时的转换搞砸了

#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;

#DST not in effect
my $utc = '2015-03-08 01:59:00.000';
my $local = utc_to_local($utc);
print "DST not in effect: utc($utc) = local($local)\n";

#DST not in effect
$utc = '2015-03-08 02:00:00.000';
$local = utc_to_local($utc);
print "DST not in effect: utc($utc) = local($local)\n";


sub utc_to_local
{
    my $utc_ts = $_[0]; #this has ms on right side, we want left 19 characters
    $utc_ts = substr $utc_ts, 0, 19;
    my $local_tp = localtime->strptime( $utc_ts, '%Y-%m-%d %H:%M:%S' );
    $local_tp = $local_tp + $local_tp->tzoffset();

    return $local_tp->strftime('%Y-%m-%d %H:%M:%S');
}
如您所见,如果我尝试在3/8的UTC凌晨1:59和3/8的UTC凌晨2点,它会认为已经发生了变化,但UTC凌晨2点仅为下午9点的3/7。远离夏令时转换,它可以正确地进行-5和-4偏移

DST not in effect: utc(2015-03-08 01:59:00.000) = local(2015-03-07 20:59:00)
DST not in effect: utc(2015-03-08 02:00:00.000) = local(2015-03-07 22:00:00)

$utc\u ts
不是本地时间

my $local_tp = localtime->strptime( $utc_ts, '%Y-%m-%d %H:%M:%S' );
应该是

my $utc_tp = Time::Piece->strptime( $utc_ts, '%Y-%m-%d %H:%M:%S' );
my $local_tp = localtime($utc_tp->epoch);

然后是转换为本地时间的问题

$local_tp = $local_tp + $local_tp->tzoffset();
应该是

my $utc_tp = Time::Piece->strptime( $utc_ts, '%Y-%m-%d %H:%M:%S' );
my $local_tp = localtime($utc_tp->epoch);

总而言之:

#!/usr/bin/perl
use strict;
use warnings;
use POSIX qw( );
use Time::Piece;

sub utc_to_local {
    my ($utc_ts) = @_;
    my $utc_tp = Time::Piece->strptime( $utc_ts, '%Y-%m-%d %H:%M:%S' );
    my $local_tp = localtime($utc_tp->epoch);
    return $local_tp->strftime('%Y-%m-%d %H:%M:%S');
}

sub local_to_utc {
    my ($local_ts) = @_;
    my $local_tp = Time::Piece->strptime( $local_ts, '%Y-%m-%d %H:%M:%S' );
    my $utc_tp = gmtime($local_tp->epoch);
    return $utc_tp->strftime('%Y-%m-%d %H:%M:%S');
}

{
    $ENV{TZ} = 'America/Toronto';
    POSIX::tzset();

    # DST not in effect
    my $utc = '2015-03-08 06:59:00.000';
    my $local = utc_to_local(substr($utc, 0, -4));
    print "DST not in effect: utc($utc) = local($local)\n";

    # DST not in effect
    $utc = '2015-03-08 07:00:00.000';
    $local = utc_to_local(substr($utc, 0, -4));
    print "DST not in effect: utc($utc) = local($local)\n";
}
输出:

DST not in effect: utc(2015-03-08 06:59:00.000) = local(2015-03-08 01:59:00)
DST not in effect: utc(2015-03-08 07:00:00.000) = local(2015-03-08 03:00:00)

DST更改发生在东部时间凌晨2:00,而不是UTC凌晨2:00。关键秒为2015-03-08 01:59:59东部标准时间(UTC-05:00)=2015-03-08 06:59:59 UTC,然后是2015-03-08 03:00:00东部标准时间(UTC-04:00)=2015-03-08 07:00:00 UTC。另外,
localtime
使用您当前所在的时区,而不一定是您所在的时区。@ThisSuitesBlack不正确,我理解为什么它是错误的,我只是不知道如何修复它。第二部分不是这里要考虑的问题,数据都是在东部时区生成的,但是对于更一般的解决方案来说,这是一个很好的点。太棒了,成功了。它是用《自大纪元以来的秒》作为一种我没有想到的通用翻译。