将本地时间转换为 UTC 时,如何使 Time::Piece 遵守 DST?
How to make Time::Piece respect DST when converting localtime to UTC?
我想将时间戳从本地时间转换为 GMT。我有执行此 "manually" 与 Time::Local::timelocal()
和 gmtime
的遗留代码。它有效,但我不喜欢它并且想改用 Time::Piece
。我使用 this answer 这样做(尽管他们正在反过来转换,但我能够将 +
替换为 -
:-))。
这是我的代码:
#!/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));
不幸的是,Time::Piece 代码似乎无法在夏令时正常工作。我住在德国,所以目前(spring/summer,实际上是 DST)我们是 UTC+2。对于 "April 19 2016" 上面的代码给出:
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)
这是正确的。但是对于 "Feb 19 2016"(当我们是 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)
即:gmtime(Time::Local::timelocal($timestamp))
给出正确的 1 小时偏移,而 Time::Piece
仍然给出 2 小时偏移。
这是 Time::Piece
中的错误还是我使用不当?
我知道有很多方法可以将本地时间转换为 UTC,但我想使用 Time::Piece
,因为它很简单。另外,我不能使用 DateTime
,因为那样会涉及将它部署到十几台生产机器上。
问题 1
localtime
returns 现在,所以 localtime->tzoffset()
returns 现在的偏移量。变化
my $utc_tp = $local_tp - localtime->tzoffset();
至
my $utc_tp = $local_tp - $local_tp->tzoffset();
但是,这会使 $utc_tp
标记为本地时间,因此您确实需要:
my $utc_tp = gmtime( $local_tp->epoch );
问题 2
尽管它的名字,$local_tp
不是本地时间,所以 $local_tp->tzoffset()
是零。变化
Time::Piece->strptime( $local_ts, '%y-%m-%d %H:%M:%S' )
至
localtime->strptime( $local_ts, '%y-%m-%d %H:%M:%S' );
我想将时间戳从本地时间转换为 GMT。我有执行此 "manually" 与 Time::Local::timelocal()
和 gmtime
的遗留代码。它有效,但我不喜欢它并且想改用 Time::Piece
。我使用 this answer 这样做(尽管他们正在反过来转换,但我能够将 +
替换为 -
:-))。
这是我的代码:
#!/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));
不幸的是,Time::Piece 代码似乎无法在夏令时正常工作。我住在德国,所以目前(spring/summer,实际上是 DST)我们是 UTC+2。对于 "April 19 2016" 上面的代码给出:
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)
这是正确的。但是对于 "Feb 19 2016"(当我们是 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)
即:gmtime(Time::Local::timelocal($timestamp))
给出正确的 1 小时偏移,而 Time::Piece
仍然给出 2 小时偏移。
这是 Time::Piece
中的错误还是我使用不当?
我知道有很多方法可以将本地时间转换为 UTC,但我想使用 Time::Piece
,因为它很简单。另外,我不能使用 DateTime
,因为那样会涉及将它部署到十几台生产机器上。
问题 1
localtime
returns 现在,所以 localtime->tzoffset()
returns 现在的偏移量。变化
my $utc_tp = $local_tp - localtime->tzoffset();
至
my $utc_tp = $local_tp - $local_tp->tzoffset();
但是,这会使 $utc_tp
标记为本地时间,因此您确实需要:
my $utc_tp = gmtime( $local_tp->epoch );
问题 2
尽管它的名字,$local_tp
不是本地时间,所以 $local_tp->tzoffset()
是零。变化
Time::Piece->strptime( $local_ts, '%y-%m-%d %H:%M:%S' )
至
localtime->strptime( $local_ts, '%y-%m-%d %H:%M:%S' );