perl datetime在dst timezone中添加月份失败

时间:2014-11-20 11:38:30

标签: perl datetime timezone dst

这两行是测试数据

 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库本身不会这样做? 如果我的解决方案是正确的,则无需回答此问题;)

由于

3 个答案:

答案 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