这两行是测试数据
my $dt = DateTime->new( {
year => 2014, month => 9, day => 19,
hour => 00, minute=> 00, second=> 00});
$dt->set_time_zone(DateTime::TimeZone->new( name => 'America/Sao_Paulo' ));
现在我想添加一个月的日期失败
$dt->add ( months => 1 );
# This fails because the result date is 2014-10-19 00:00:00 and for Sao_Paulo
# the result should be a DST shifted time 2014-10-19 01:00:00
我提出的最简单的解决方案是
my $tz_backup = $dt->time_zone(); # Backup the timezone
$dt->set_time_zone('UTC'); # Moving the time to UTC to get rid of DST complexities
$dt->add ( months => 1 ); # Perform the original operation
$dt->set_time_zone($tz_backup); # Setting back the original timezone
问题是,这个解决方案中有任何缺陷吗?
如果这种方法对于所有时区和所有DST场景都是正确的,那么为什么perl DateTime库本身不会这样做? 如果我的解决方案是正确的,则无需回答此问题;)
由于
答案 0 :(得分:1)
为什么图书馆不会自己做呢?因为一个月不一定的秒数,所以它是一定的(按月变化)天数。如果你想要的是添加一个月的秒,你可以这样做:
my $dt = DateTime->new( year => 2014, month => 9, day => 19, time_zone => 'America/Sao_Paulo' );
$dt->add( seconds => DateTime->last_day_of_month( year => $dt->year, month => $dt->month )->day * 24 * 60 * 60 );
或者只是按照你的建议使用UTC。
答案 1 :(得分:0)
建议您在documentation中使用您的解决方案,因此应该没问题。
另外,当我运行原始代码时,我收到了错误:
Invalid local time for date in time zone: America/Sao_Paulo
答案 2 :(得分:0)
如果这种方法对所有时区和所有DST场景都非常正确
正确的做法是什么?
一个月后获取日期时间?不,这会产生错误的结果。
使用DateTime进行日期算术?我使用“浮动”代替“UTC”,这使您无需转换回来。使用UTC也会给你错误的结果。
$ perl -MDateTime -E'
my $dt = DateTime->now( time_zone => "America/Toronto" )->set_hour(0);
say $dt->ymd;
say $dt->clone
->set_time_zone("UTC")
->truncate( to => "day" )
->set_time_zone("America/Toronto")
->ymd;
say $dt->clone
->set_time_zone("floating")
->truncate( to => "day" )
->ymd;
'
2014-11-20
2014-11-19 # XXX
2014-11-20
那为什么perl DateTime库本身不会这样做?
你要求它在一个月后给DT。如果在没有被告知的情况下给出一个月和一个小时是不正确的。
换句话说,人们希望增加功能如下:
timestamp + duration - duration = timestamp