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

由于DST时钟向前,perl DateTime和不存在的时间用户输入,perl,datetime,dst,Perl,Datetime,Dst,如果我们知道用户的时区和日期,但用户在文本框(即用户选择日期但键入时间的日历)中输入时间,在正确解析后,我们知道小时和分钟,我们应该如何处理由于DST时钟向前而不存在的时间(例如,02:00不存在,因为时钟向前拨了1小时)以便将它(至少存在一个小时)传递到DateTime->new() 错误:时区中日期的本地时间无效:欧洲/柏林 当您进入夏令时,没有问题。假设DLS在虚拟时区ATZ(一个时区)的给定日期凌晨2点开始,偏移量为N小时,那么从凌晨2点前1秒开始的3秒将被时间戳标记 1:59:59 A

如果我们知道用户的时区和日期,但用户在文本框(即用户选择日期但键入时间的日历)中输入时间,在正确解析后,我们知道小时和分钟,我们应该如何处理由于DST时钟向前而不存在的时间(例如,02:00不存在,因为时钟向前拨了1小时)以便将它(至少存在一个小时)传递到DateTime->new()

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


当您进入夏令时,没有问题。假设DLS在虚拟时区ATZ(一个时区)的给定日期凌晨2点开始,偏移量为N小时,那么从凌晨2点前1秒开始的3秒将被时间戳标记

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的开始,您的接口必须拒绝引用关键时刻的条目

在DateTime文档的前面,有一个建议——出于性能原因——确定一次本地时区,然后在整个应用程序中使用它

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

... # then everywhere else

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

…但这将使您再次容易受到此问题的影响。由于您的界面必须知道其DLS日的开始或结束,因此您可以按照建议设置并使用$App::LocalTZ,然后在DLS日结束时使用特定的提示时区进行覆盖。

这不是编程问题。我不会让用户输入invalid日期,即拒绝日期,并且内部仅使用UTC。我是指时间,而不是日期,对此表示抱歉。但是谁拒绝像
53:69
?你不能让那一方也拒绝
02:30
?只是在菜里加一点胡椒粉:你对“备份”怎么办TZ从DST返回的时间?-故事的寓意:本地时间的任何输入都会受到质疑,除非它是根据基本TZ的约定进行的。本规范包括DS切换发生的时间,可用于验证并最终将用户输入转换为UTC。“由于DST时钟向前,我们应该如何处理不存在的时间"通知用户他们输入的时间无效,并要求他们输入有效的时间。这并不能真正回答问题。此外,DST更改前后的3秒将是01:59:59 ATZ、03:00:00 ADZ、03:00:01 ADZ(输入时)和01:59:59 ADZ、01:00:00 ATZ、01:00:01 ATZ(离开时)。我太粗心了-谢谢提示。这就是我的意思是键入,但我复制了每一行,没有聚焦区域、偏移量和秒数,忘记了小时数。为什么不回答这个问题?调用构造函数时,您必须始终提供区域。问题是,当用户输入无效时间时,我该怎么办?(例如,在您的示例中,DST的第一天02:00:00 ADZ)OP已经在构造函数中通过了时区。我试图让它更清楚。谢谢你建设性的、有用的和准确的批评。
our $App::LocalTZ = DateTime::TimeZone->new( name => 'local' );

... # then everywhere else

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