由于DST时钟转发,perl DateTime和不存在的用户输入时间

时间:2016-03-26 16:12:37

标签: perl datetime dst

在我们知道用户的时区和日期的情况下,但是用户在文本框中输入时间(即用户选择日期但是键入时间的日历),在正确解析之后我们知道小时和分钟,我们应该如何处理由于DST时钟前进而不存在的时间(例如,由于时钟向前转1小时而不存在02:00)以便通过它 - 至少存在hour-to DateTime-> new();?

use DateTime;
$dt = DateTime->new(
    year   => $year_userinput,  #2016
    month  => $month_userinput,  #03
    day    => $day_userinput,  #27
    hour   => $hour_userinput,  #02
    minute => $minute_userinput,  #30
    second => 0,
    time_zone => $timezone_userinput,  #Europe/Berlin
);
  

错误:时区中日期的本地时间无效:欧洲/柏林

1 个答案:

答案 0 :(得分:0)

当你进入夏令时,没有问题。假设DLS在虚拟时区的某一天的凌晨2点开始,ATZ(一个时区)的偏移量为N小时,则凌晨2点开始的三秒钟开始加时间戳;

1:59:59 ATZ +N
3:00:00 ADZ +(N+1)
3:00:01 ADZ +(N+1)

......当出现夏令时......

2:00:00 ADZ +(N+1)
2:00:01 ADZ +(N+1)
...
... about an hour later
...
2:59:59 ADZ +(N+1)
2:00:00 ATZ +N
2:00:01 ATZ

似乎有一个更早的" 2:00:01"但是这包括(N + 1)的偏移 - 或者在时区ADZ中 - 而这个在ATZ(N)中。 DateTime模块引发了这样的问题:

不明确的当地时间

由于夏令时,可以指定不明确的本地时间。例如,在2003年的美国,从保存到标准时间的过渡发生在当地时间10月26日02:00:00。本地时钟从01:59:59(节省时间)更改为01:00:00(标准时间)。这意味着从01:00:00到01:59:59的小时实际上发生了两次,但UTC时间继续向前移动。

要避免此问题,您必须在创建时间对象时始终包含时区或偏移量。要做到这一点,你需要使用日期(你说你有它)来检测它是DLS结束日,如果用户选择了在关键时刻内的时间,你将会有提示"是ADZ的凌晨2:30还是ATZ的凌晨2:30?"或类似的东西。同样,如果它是DLS的开始,您的界面必须拒绝引用关键时刻的条目。

早些时候在日期时间的doco中,出于性能原因,建议一次确定本地时区,然后在整个应用程序中使用它;

our $App::LocalTZ = DateTime::TimeZone->new( name => 'local' );

... # then everywhere else

my $dt = DateTime->new( ..., time_zone => $App::LocalTZ );

...但这会让你再次容易受到这个问题的影响。由于您的界面必须知道其DLS开始日或DLS结束日,您可以按照建议设置和使用$ App :: LocalTZ,然后覆盖特定的,提示的时区,如果它&# 39;结束了DLS日。