我希望将这个问题及其答案作为处理夏令时的最终指南,特别是处理实际转换时。

如果你有什么要补充的,请做

许多系统都依赖于保持准确的时间,问题是由于夏时制而导致的时间变化——向前或向后移动时钟。

例如,一个订单接受系统中的业务规则取决于订单的时间——如果时钟发生变化,规则可能就不那么清晰了。应如何保持订单的时间?当然,有无数的场景——这只是一个例证。

你是如何处理日光节约问题的?您的解决方案包含哪些假设?(在此处查找上下文)

同样重要,如果不是更重要的话:

你尝试了什么但没有奏效?为什么不起作用?

我会对编程、操作系统、数据持久性和其他相关方面感兴趣。

一般的答案很好,但我也希望看到细节,特别是如果它们只在一个平台上提供的话。


当前回答

如果您的设计能够适应,请避免同时转换本地时间!

我知道对一些人来说,这可能听起来很疯狂,但想想用户体验:用户处理接近的相对日期(今天、昨天、下周一)比绝对日期(2010.09.17,星期五-9月17日)的速度要快。当你仔细考虑时,时区(和DST)的准确度越接近现在()就越重要,所以如果你可以用+/-1或2周的相对格式表示日期/日期时间,其余的日期可以是UTC,这对95%的用户来说并不重要。

通过这种方式,您可以以UTC存储所有日期,并以UTC进行相对比较,只需向用户显示超出相对日期阈值的UTC日期。

这也适用于用户输入(但通常以更有限的方式)。从只有{昨天、今天、明天、下周一、下周四}的下拉列表中进行选择,对于用户来说,比日期选择器更简单、更容易。日期选择器是表单填充中最令人痛苦的部分。当然,这并不适用于所有情况,但您可以看到,它只需要一点巧妙的设计就可以使其非常强大。

其他回答

PHP的DateTimeZone::listAbstrations()输出

此PHP方法返回一个包含一些“主要”时区(如CEST)的关联数组,这些时区本身包含更具体的“地理”时区(例如欧洲/阿姆斯特丹)。

如果您使用这些时区及其偏移/DST信息,请务必了解以下信息:

似乎每个时区的所有不同偏移量/DST配置(包括历史配置)都包含在内!

例如,欧洲/阿姆斯特丹可以在该函数的输出中找到六次。两次出现(偏移量1172/4772)是1937年之前使用的阿姆斯特丹时间;两个(1200/4800)用于1937年至1940年间使用的时间;两个(3600/4800)是1940年以来使用的时间。

因此,您不能依赖此函数返回的当前正确/正在使用的偏移量/DST信息!

如果您想知道某个时区的当前偏移量/DST,您必须执行以下操作:

<?php
$now = new DateTime(null, new DateTimeZone('Europe/Amsterdam'));
echo $now->getOffset();
?>

您需要了解Olson-tz数据库,可从ftp://elsie.nci.nih.gov/pub http://iana.org/time-zones/.它每年更新多次,以应对世界各地不同国家在冬季和夏季(标准时间和夏令时)之间切换的时间(以及是否切换)的最后时刻变化。2009年,最后一次发布是2009年;2010年为2010n;2011年为2011n;2012年5月底,发布时间为2012c。注意,在两个独立的存档(tzcode20xxy.tar.gz和tzdata20xxy.tar.gz)中有一组代码来管理数据和实际时区数据本身。代码和数据都在公共域中。

这是时区名称的来源,如America/Los_Angeles(和同义词,如US/Pacific)。

如果你需要跟踪不同的区域,那么你需要奥尔森数据库。正如其他人所建议的,您还希望以固定格式(UTC通常是所选的格式)存储数据,并记录生成数据的时区。您可能需要区分时间与UTC的偏移量和时区名称;这会在以后产生影响。此外,知道当前是2010-03-28T23:47:00-07:00(美国/太平洋)可能会或可能不会帮助您解释值2010-11-15T12:30-这可能是在PST(太平洋标准时间)而不是PDT(太平洋夏令时)中指定的。

标准的C库接口对这类东西没有太大的帮助。


奥尔森的数据发生了变化,部分原因是A·D·奥尔森很快就要退休了,另一部分原因是对维护者的版权侵权诉讼(现已驳回)。时区数据库现在由互联网号码分配机构IANA负责管理,并且在首页有一个“时区数据库”链接。讨论邮件列表现在是tz@iana.org; 公告列表是tz-announce@iana.org.

商业规则应始终适用于民事诉讼时间(除非法律另有规定)。请注意,公民时间是一团糟,但这是人们使用的时间,所以这才是最重要的。

在内部,将时间戳保持在从大纪元开始的民用时间秒中。纪元并不特别重要(我喜欢Unix纪元),但它确实比其他纪元更容易。假装闰秒不存在,除非你正在做一些真正需要它们的事情(例如,卫星跟踪)。时间戳和显示时间之间的映射是应用DST规则的唯一点;规则经常变化(在全球范围内,一年几次;指责政客),所以你应该确保你没有硬编码地图。奥尔森的TZ数据库是无价的。

这是一个重要而令人惊讶的棘手问题。事实是,对于坚持时间没有完全令人满意的标准。例如,SQL标准和ISO格式(ISO 8601)显然不够。

从概念角度来看,通常处理两种类型的时间-日期数据,区分它们很方便(上述标准没有):“物理时间”和“民事时间”。

时间的“物理”瞬间是物理学处理的连续宇宙时间线中的一个点(当然忽略了相对论)。例如,如果可以忽略闰秒,则可以在UTC中对这个概念进行适当的编码。

“民用”时间是遵循民用规范的日期时间规范:这里的时间点完全由一组日期时间字段(Y、M、D、H、MM、S、FS)加上TZ(时区规范)(实际上也是“日历”;但假设我们将讨论限于公历)来指定。时区和日历共同允许(原则上)从一个表示映射到另一个表示。但是,民用和物理时间瞬间是本质上不同类型的量值,它们应该在概念上分开并以不同的方式对待(一个类比:字节和字符串的数组)。

这个问题令人困惑,因为我们可以互换地谈论这些类型的事件,并且因为公民时代会受到政治变化的影响。这个问题(以及区分这些概念的必要性)在未来的事件中变得更加明显。示例(摘自我在这里的讨论。

约翰在日历上记录了某个日期的事件提醒2019-Jul-27,10:30:00,TZ=智利/圣地亚哥,(已偏移GMT-4,因此它对应于UTC 2019-Jul-27 14:30:00)。但总有一天未来,该国决定将TZ偏移量改为GMT-5。

现在,当这一天到来。。。该提醒是否应在

A) 2019-Jul-27 10:30:00智利/圣地亚哥=UTC时间2019-Jur-27 15:30:00?

or

B) 2019-Jul-27 9:3:00智利/圣地亚哥=UTC时间2019-Jul-27 14:30:00?

没有正确的答案,除非你知道约翰在概念上的意思当他告诉日历“请在2019年7月27日10:30:00给我打电话TZ=智利/圣地亚哥”。

他是说“公民约会时间”吗10:30“)?在这种情况下,A)是正确答案。

或者他是指“物理上的瞬间”,连续波中的一个点我们宇宙的时间线,比如,“下一次日食在这种情况下,答案B)是正确的。

一些Date/Time API正确地实现了这一区别:其中的Jodatime是下一个(第三个!)Java DateTime API(JSR 310)的基础。

通常,在存储的时间戳中包含本地时间偏移量(包括DST偏移量):如果您以后想在原始时区(和DST设置)中显示时间戳,仅使用UTC是不够的。

请记住,偏移量并不总是整数小时(例如,印度标准时间为UTC+05:30)。

例如,合适的格式是元组(unix时间,以分钟为单位的偏移量)或ISO 8601。