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

Posted

技术标签:

【中文标题】由于 DST 时钟向前,perl DateTime 和不存在的时间用户输入【英文标题】:perl DateTime and non-existent time user input because of DST clock forward 【发布时间】:2016-07-14 06:03:24 【问题描述】:

在我们知道用户的时区和日期但时间由用户在文本框(即用户选择日期但键入时间的日历)中输入的场景中,经过正确解析和我们知道小时和分钟,我们应该如何处理由于 DST 时钟向前不存在的时间(例如,02:00 不存在,因为时钟向前 1 小时)以便通过它 - 至少存在小时到 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
);

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

【问题讨论】:

不是编程问题。 我不会让用户输入无效的日期,即拒绝它们,并且在内部只使用 UTC。 我的意思是 time,而不是 date,抱歉。但是拒绝像53:69这样的时间?你不能让那个派对也拒绝02:30吗? 只是在菜里加点辣椒:TZ从夏令时返回的“备份”时间你会做什么? - 故事的寓意:当地时间的任何输入都会受到质疑,除非它是根据底层 TZ 的一个易于理解的约定进行的。该规范包括 DS 切换发生的时间,可用于验证并最终将用户输入转换为 UTC。 "由于 DST 时钟向前,我们应该如何处理不存在的时间" 通知用户他们输入的时间无效并要求他们输入有效时间。 【参考方案1】:

当您进入夏令时时,没有问题。假设 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 结束日,如果用户选择了关键时间内的时间,您将不得不提示“那是凌晨 2:30 ADZ 还是凌晨 2:30 ATZ?”或类似的东西。同样,如果它是 DLS 的开始,您的界面必须拒绝引用关键时间的条目。

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

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

... # then everywhere else

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

...但这会让您再次受到该问题的影响。由于您的界面必须知道其 DLS 开始日或 DLS 结束日,您可以按照建议设置和使用 $App::LocalTZ,然后在结束时使用特定的提示时区覆盖-DLS 日。

【讨论】:

这并不能真正回答问题。此外,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 已经在构造函数中传递时区。 我试图让它更清楚。感谢您的建设性、有用和准确的批评。

以上是关于由于 DST 时钟向前,perl DateTime 和不存在的时间用户输入的主要内容,如果未能解决你的问题,请参考以下文章

计算 DST 转换边界处的持续时间(向前/后退的数量)

考虑时钟变化设置正确的 UTC DateTime

设计开发 典型异步电路设计-脉冲同步

通过 GMT 偏移值 DST 更改/转换 DateTime 是不是安全? [关闭]

Rails 使用时区参数和 DST 强制执行 DateTime 偏移

.Net DateTime 与本地时间和 DST