如何在将本地时间转换为UTC时使Time :: Piece尊重DST?

Per*_*uck 7 perl datetime dst

我想将时间戳从本地时间转换为GMT.我有遗留代码,使用Time::Local::timelocal()和"手动"执行此操作gmtime.它有效,但我不喜欢它,Time::Piece而是想用它代替.我用这个答案这样做(虽然他们正在转换,但我能够+-:-) 取代).

这是我的代码:

#!/usr/bin/env perl

use strict;
use warnings;
use Time::Local;
use Time::Piece;
use POSIX qw(strftime);

sub local_to_utc_timelocal
{
    my $local_ts = shift;
    my ( $year, $mon, $mday, $hour, $min, $sec ) 
        = ( $local_ts =~ /(\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/ );
    my $local_secs = Time::Local::timelocal( $sec, $min, $hour, $mday, $mon - 1, $year );
    return POSIX::strftime( '%y-%m-%d %H:%M:%S', gmtime($local_secs) );
}

sub local_to_utc_timepiece
{
    my $local_ts = shift;
    my $local_tp = Time::Piece->strptime( $local_ts, '%y-%m-%d %H:%M:%S' );
    my $utc_tp   = $local_tp - localtime->tzoffset(); # ***
    return $utc_tp->strftime('%y-%m-%d %H:%M:%S');
}

my $local;

# DST in effect (April 19 2016):
$local = '16-04-19 14:30:00';
print "DST in effect:\n";
printf("utc(%s) = %s (using timelocal)\n", $local, local_to_utc_timelocal($local));
printf("utc(%s) = %s (using timepiece)\n\n", $local, local_to_utc_timepiece($local));

# DST NOT in effect (Feb 19 2016):
$local = '16-02-19 14:30:00';
print "DST NOT in effect:\n";
printf("utc(%s) = %s (using timelocal)\n", $local, local_to_utc_timelocal($local));
printf("utc(%s) = %s (using timepiece)\n", $local, local_to_utc_timepiece($local));
Run Code Online (Sandbox Code Playgroud)

不幸的是,Time :: Piece代码似乎无法正常使用DST.我住在德国,所以目前(春/夏,DST有效)我们是UTC + 2.对于"2016年4月19日",上述代码给出:

DST in effect:
utc(16-04-19 14:30:00) = 16-04-19 12:30:00 (using timelocal)
utc(16-04-19 14:30:00) = 16-04-19 12:30:00 (using timepiece)
Run Code Online (Sandbox Code Playgroud)

哪个是对的.但对于"2016年2月19日"(当我们是UTC + 1时),相同的代码给出:

DST NOT in effect:
utc(16-02-19 14:30:00) = 16-02-19 13:30:00 (using timelocal)
utc(16-02-19 14:30:00) = 16-02-19 12:30:00 (using timepiece)
Run Code Online (Sandbox Code Playgroud)

即:gmtime(Time::Local::timelocal($timestamp))给出正确的1小时偏移,同时Time::Piece仍然给出2小时的偏移.

这是一个错误,Time::Piece还是我错误地使用它?

我知道有很多方法可以将localtime转换为UTC,但我想使用它Time::Piece因为它的简单性.另外,我无法使用,DateTime因为这将涉及在十几台生产机器上部署它.

ike*_*ami 8

问题1

localtime现在返回,所以现在localtime->tzoffset()返回偏移量.更改

my $utc_tp = $local_tp - localtime->tzoffset();
Run Code Online (Sandbox Code Playgroud)

my $utc_tp = $local_tp - $local_tp->tzoffset();
Run Code Online (Sandbox Code Playgroud)

但是,这$utc_tp标记为本地时间,所以你真的想要:

my $utc_tp = gmtime( $local_tp->epoch );
Run Code Online (Sandbox Code Playgroud)

问题2

尽管它的名字,$local_tp不是当地时间,所以$local_tp->tzoffset()是零.更改

Time::Piece->strptime( $local_ts, '%y-%m-%d %H:%M:%S' )
Run Code Online (Sandbox Code Playgroud)

localtime->strptime( $local_ts, '%y-%m-%d %H:%M:%S' );
Run Code Online (Sandbox Code Playgroud)

  • 扩展"`$ local_tp`不是本地时间":如果你将`strptime`称为类方法(即`Time :: Piece-> strptime`)并且没有用`%指定格式的时区假定为z`或`%Z`,UTC.另一方面,如果将`strptime`称为对象方法(例如`localtime-> strptime`),则使用对象的时区. (2认同)