我希望能够将这个问题及其答案作为处理夏令时的权威指南,特别是处理实际的变更问题。
如果您有任何要添加的内容,请执行此操作
许多系统依赖于保持准确的时间,问题在于由于夏令时而改变时间 - 向前或向后移动时钟。
例如,一个订单系统中的业务规则取决于订单的时间 - 如果时钟发生变化,规则可能不那么明确。如何保持订单的时间?当然有无数的场景 - 这只是一个说明性的场景。
同样重要的是,如果不是这样的话:
我会对编程,操作系统,数据持久性以及该问题的其他相关方面感兴趣。
一般答案很棒,但我也希望看到细节,特别是如果它们只在一个平台上可用。
Do:
datetimeoffset
type that can store both in a single field.1970-01-01T00:00:00Z
(excluding leap seconds). If you require higher precision, use milliseconds instead. This value should always be based on UTC, without any time zone adjustment.DateTimeOffset
is often a better choice than DateTime
.DateTime
, and DateTimeZone
classes. Be careful when using DateTimeZone::listAbbreviations()
- see answer. To keep PHP with up to date Olson data, install periodically the timezonedb PECL package; see answer.>=
, <
).Don't:
America/New_York
with a "time zone offset", such as -05:00
. They are two different things. See the timezone tag wiki.Date
object to perform date and time calculations in older web browsers, as ECMAScript 5.1 and lower has a design flaw that may use daylight saving time incorrectly. (This was fixed in ECMAScript 6 / 2015).Testing:
Reference:
timezone
标签维基页面 dst
timezone
其他:
我不确定我可以添加到上面的答案,但这里有几点我:
您应该考虑四种不同的时间:
还有历史 / 交替时间。这些都很烦人,因为它们可能无法映射回标准时间。例如:朱利安日期,日期根据土星的农历,克林贡日历。
以 UTC 格式存储开始 / 结束时间戳的效果很好。对于 1,您需要与事件一起存储的事件时区名称 + 偏移量。对于 2,您需要为每个区域存储一个本地时间标识符和为每个查看器存储的本地时区名称 + 偏移量(如果您处于紧缩状态,则可以从 IP 中获取此值)。对于 3,以 UTC 秒存储,不需要时区。 4 是 1 或 2 的特殊情况,具体取决于它是全局还是本地事件,但您还需要存储在时间戳中创建的内容,以便您可以判断在创建此事件之前或之后是否更改了时区定义。如果您需要显示历史数据,这是必要的。
以上的一个例子是:
足球世界杯决赛比赛于 2010 年 7 月 11 日 19:00 UTC 在南非(UTC + 2 - SAST)举行。
有了这些信息,我们可以历史地确定 2010 WCS 决赛发生的确切时间,即使南非时区定义发生变化, 并且能够在查询数据库时向当地时区的观众显示。
您还需要使您的操作系统,数据库和应用程序 tzdata 文件保持同步,彼此之间以及与世界其他地方同步,并在升级时进行广泛测试。您依赖的第三方应用程序未正确处理 TZ 更改并非闻所未闻。
确保硬件时钟设置为 UTC,如果您在世界各地运行服务器,请确保其操作系统也配置为使用 UTC。当您需要从多个时区的服务器复制每小时轮换的 apache 日志文件时,这一点就变得很明显了。按文件名对它们进行排序仅在所有文件都使用相同的时区命名时才有效。这也意味着当您从一个框转到另一个框并且需要比较时间戳时,您不必在头脑中进行日期数学运算。
此外,在所有框上运行 ntpd。
永远不要相信从客户端计算机获得的时间戳有效。例如,Date:HTTP 标头或 javascript Date.getTime()
调用。当用作不透明标识符时,或者在同一客户端上的单个会话期间进行日期数学运算时,这些都很好,但不要尝试将这些值与服务器上的内容交叉引用。您的客户端不运行 NTP,并且可能不一定有可用于其 BIOS 时钟的电池。
最后,政府有时会做很奇怪的事情:
从 1909-05-01 到 1937-06-30,荷兰的标准时间恰好是 UTC 的 19 分和 32.13 秒。使用 HH:MM 格式无法准确表示此时区。
好的,我想我已经完成了。
这是一个重要且令人惊讶的棘手问题。事实上,没有完全令人满意的持久时间标准。例如,SQL 标准和 ISO 格式(ISO 8601)显然是不够的。
从概念的角度来看,人们通常会处理两种类型的时间 - 数据,并且很容易区分它们(上述标准没有):“ 物理时间 ” 和 “ 民用时间 ”。
“物理” 时刻是物理学处理的连续通用时间线中的一个点(当然,忽略相对论)。例如,这个概念可以用 UTC 充分编码 - 持久化(如果你可以忽略闰秒)。
“民用” 时间是遵循民用规范的日期时间规范:此处的时间点由一组日期时间字段(Y,M,D,H,MM,S,FS)加上 TZ(时区规范)完全指定(实际上也是 “日历”; 但我们假设我们将讨论限制在格里高利历)。时区和日历共同允许(原则上)从一个表示映射到另一个表示。但是,民用和物理时间瞬间是不同类型的大小,它们应该在概念上保持分离和区别对待(类比:字节数组和字符串)。
这个问题令人困惑,因为我们可以互换地谈论这些类型的事件,因为民事时代受政治变化的影响。对于未来的事件,问题(以及区分这些概念的必要性)变得更加明显。例子(取自我在这里的讨论。
约翰在他的日历中记录了2019-Jul-27, 10:30:00
,TZ = Chile/Santiago
某些事件的提醒(其偏移 GMT-4,因此它对应于 UTC 2019-Jul-27 14:30:00
)。但是在未来的某一天,该国决定将 TZ 抵消额改为 GMT-5。
现在,当这一天到来时... 那个提醒应该触发
A) 2019-Jul-27 10:30:00 Chile/Santiago
= UTC time 2019-Jul-27 15:30:00
?
要么
B) 2019-Jul-27 9:30:00 Chile/Santiago
= UTC time 2019-Jul-27 14:30:00
?
没有正确的答案,除非在他告诉日历 “请在2019-Jul-27, 10:30:00 TZ=Chile/Santiago
给我打电话” 时,知道约翰的概念意味着什么。
他的意思是 “民事约会时间”(“我所在城市的时钟告诉 10:30”)?在这种情况下,A)是正确的答案。
或者他的意思是 “物理瞬间的时间”,这是我们宇宙的连续时间线中的一个点,比如说,“当下一次日食发生时”。在这种情况下,答案 B)是正确的。
一些日期 / 时间 API 正确地获得了这一区别:其中包括Jodatime ,它是下一个(第三个!)Java DateTime API(JSR 310)的基础。