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

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

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

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

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

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

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

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

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


当前回答

对于PHP:

PHP>5.2中的DateTimeZone类已经基于其他人提到的Olson DB,因此,如果您在PHP中而不是在DB中进行时区转换,则不必使用(难以理解的)Olson文件。

然而,PHP的更新频率不如Olson DB,因此仅使用PHPs时区转换可能会给您留下过时的DST信息,并影响数据的正确性。虽然这种情况预计不会经常发生,但如果您在全球拥有大量用户,这种情况可能会发生。

要解决上述问题,请使用timezonedb pecl包。它的功能是更新PHP的时区数据。根据更新的频率安装此软件包。(我不确定这个软件包的更新是否完全遵循奥尔森的更新,但它的更新频率似乎至少非常接近奥尔森更新的频率。)

其他回答

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

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

明确关注点的架构分离-准确地知道哪个层与用户交互,并且必须更改规范表示(UTC)的日期时间。非UTC日期时间是表示(遵循用户本地时区),UTC时间是模型(对于后端和中间层仍然是唯一的)。

此外,决定你的实际受众是什么,你不需要服务什么,你在哪里划分界限。除非你在那里有重要的客户,否则不要接触异国情调的日历,然后考虑为该地区单独的面向用户的服务器。

若您可以获取并维护用户的位置,则可以使用位置进行系统的日期时间转换(例如.NET区域性或SQL表),但如果日期时间对您的用户至关重要,则为最终用户提供一种选择覆盖的方式。

如果涉及历史审计义务(例如准确地告诉亚利桑那州的Jo在2年前的9月支付账单的时间),则记录UTC和当地时间(您的转换表会随着时间的推移而改变)。

为批量提供的数据(如文件、web服务等)定义时间参考时区。如果东海岸公司在加利福尼亚州设有数据中心,您需要询问并了解他们使用什么作为标准,而不是假设其中之一。

不要相信嵌入在日期时间文本表示中的时区偏移,也不要接受解析和跟踪它们。相反,始终要求明确定义时区和/或参考区域。你可以很容易地用PST偏移量接收时间,但时间实际上是EST,因为这是客户端的参考时间,记录只是在PST中的服务器上导出的。

答案和其他数据摘要:(请添加您的答案)

Do:

无论何时,只要你指的是一个确切的时刻,都要根据不受夏令时影响的统一标准坚持时间。(GMT和UTC在这方面相当,但最好使用UTC一词。请注意,UTC也被称为祖鲁时间或Z时间。)相反,如果您选择使用本地时间值保存一个(过去的)时间,请包括该特定时间与UTC的本地时间偏移量(该偏移量可能会在一年中发生变化),以便以后可以明确地解释时间戳。在某些情况下,您可能需要同时存储UTC时间和等效的本地时间。通常这是通过两个单独的字段来完成的,但有些平台支持datetimeoffset类型,可以将这两个字段存储在一个字段中。当将时间戳存储为数值时,请使用Unix时间-这是自1970-01-01T00:00:00Z以来的整秒数(不包括闰秒)。如果需要更高的精度,请改用毫秒。该值应始终基于UTC,不进行任何时区调整。如果以后可能需要修改时间戳,请包括原始时区ID,以便确定偏移量是否与记录的原始值发生了变化。在安排未来事件时,通常首选当地时间而不是UTC,因为偏移量通常会发生变化。请参阅答案和博客文章。存储整个日期(如生日和周年纪念日)时,不要转换为UTC或任何其他时区。如果可能,请存储不包含时间的仅日期数据类型。如果这种类型不可用,请确保在解释值时始终忽略一天中的时间。如果您不能保证一天中的时间会被忽略,请选择中午12:00,而不是午夜00:00作为当天更安全的代表时间。请记住,时区偏移并不总是整数小时(例如,印度标准时间为UTC+05:30,尼泊尔使用UTC+05:45)。如果使用Java,请将Java.time用于Java 8和更高版本。java.time的大部分功能在ThreeTen Backport库中被向后移植到java 6和7。进一步适用于ThreeTenABP库中的早期Android(<26)。这些项目正式取代了现在处于维护模式的久负盛名的Joda Time。Joda Time、ThreeTen Backport、ThreeTen-Extra、java.Time类和JSR 310由同一个人Stephen Colebourne领导。如果使用.NET,请考虑使用Noda Time。如果使用没有Noda Time的.NET,请考虑DateTimeOffset通常比DateTime更好。如果使用Perl,请使用DateTime。如果使用Python 3.9或更高版本,请使用内置的zoneinfo处理时区。否则,请使用dateutil或arrow。通常可以避免使用较旧的pytz库。如果使用JavaScript,请避免使用旧的moment.js或moment时区库,因为它们不再被主动维护。有关详细信息,请参阅Moment.js项目状态。相反,考虑Luxon、date fns、day.js或js joda。如果使用PHP>5.2,请使用DateTime和DateTimeZone类提供的本地时区转换。使用DateTimeZone::listAb缩略语()时要小心-请参阅答案。要使PHP保持最新的Olson数据,请定期安装timezonedb PECL包;见答案。如果使用C++,请确保使用正确实现IANA时区数据库的库。其中包括cctz、ICU和霍华德·希南特的“tz”图书馆。在C++20中,后者被采用到标准<chrono>库中。不要将Boost用于时区转换。尽管其API声称支持标准IANA(又称“zoneinfo”)标识符,但它将它们粗略地映射到POSIX风格的数据,而没有考虑每个区域可能发生的丰富变化历史。(此外,该文件已无法维护。)如果使用Rust,请使用chrono。大多数业务规则使用民用时间,而不是UTC或GMT。因此,在应用应用程序逻辑之前,计划将UTC时间戳转换为本地时区。请记住,时区和偏移不是固定的,可能会改变。例如,历史上,美国和英国使用相同的日期来“向前冲”和“向后冲”。然而,在2007年,美国改变了时钟的日期。这意味着一年中的48周,伦敦时间和纽约时间相差5小时,4周(春季3小时,秋季1小时)相差4小时。在涉及多个区域的任何计算中,请注意类似的项目。考虑时间类型(实际事件时间、广播时间、相对时间、历史时间、重现时间),您需要存储哪些元素(时间戳、时区偏移和时区名称)以进行正确检索-请参阅本答案中的“时间类型”。让您的操作系统、数据库和应用程序tzdata文件在它们与世界其他地方之间保持同步。在服务器上,将硬件时钟和操作系统时钟设置为UTC,而不是本地时区。无论前面的要点是什么,服务器端代码(包括网站)都不应该期望服务器的本地时区是任何特定的。见答案。更喜欢在应用程序代码中逐个处理时区,而不是通过配置文件设置或默认值进行全局处理。在所有服务器上使用NTP服务。如果使用FAT32,请记住时间戳存储在本地时间,而不是UTC。当处理重复发生的事件(例如每周电视节目)时,请记住,时间会随着夏令时的变化而变化,并且不同时区的时间也会不同。始终将日期时间值查询为下限包含,上限不包含(>=,<)。

不要:

不要将“时区”(如美国/纽约)与“时区偏移”(如-05:00)混淆。它们是两种不同的东西。请参见时区标签wiki。不要使用JavaScript的Date对象在较旧的web浏览器中执行日期和时间计算,因为ECMAScript 5.1及更低版本有一个设计缺陷,可能会错误地使用夏时制。(这在ECMAScript 6/2015中已修复)。永远不要相信客户的时钟。这很可能是不正确的。不要告诉人们“在任何地方都要使用UTC”。这一广泛的建议是对本文档前面描述的几种有效场景的短视。相反,对正在处理的数据使用适当的时间参考。(时间戳可以使用UTC,但未来时间调度和仅日期值不应使用。)

测试:

测试时,请确保您测试了西半球、东半球、北半球和南半球的国家(事实上,在全球每四分之一的地区,共有4个地区),无论是否正在进行夏令时测试(给出8个),以及一个不使用夏令时的国家(另外4个国家覆盖所有地区,共12个)。测试DST转换,即当您当前处于夏季时,选择冬季的时间值。测试边界情况,例如UTC+12时区,夏令时,使当地时间UTC+13在夏季,甚至UTC+13的地方在冬季测试所有第三方库和应用程序,确保它们正确处理时区数据。至少测试半小时时区。

参考:

堆栈溢出上的详细时区标记wiki页面Olson数据库,又名Tz_databaseIETF奥尔森数据库维护程序草案时区和夏令时的来源ISO格式(ISO 8601)UnicodeConsortium提供的Olson数据库与Windows时区ID之间的映射维基百科上的时区页面StackOverflow问题标记为dstStackOverflow问题标记了时区处理DST-Microsoft DateTime最佳实践维基百科上的网络时间协议

其他:

游说你的代表结束DST这一令人厌恶的行为。我们总是希望。。。地球标准时间大厅

汤姆·斯科特(Tom Scott)在《计算机爱好者》频道的YouTube上关于时区的视频也对这一话题进行了精彩有趣的描述。示例包括:

萨摩亚(太平洋中的一个岛屿)将其时区提前24小时,以便于与澳大利亚和新西兰的贸易,西岸有两个人口在不同的时区,18世纪从儒略历到格里高利历的变化日历(发生在20世纪的俄罗斯)。

还有一件事,确保服务器应用了最新的夏令时补丁。

去年,我们遇到了这样一种情况,北美用户在三周内的时间里,即使我们使用的是基于UTC的系统,我们的时间也总是比以前少一个小时。

最后证明是服务器。他们只需要应用最新的修补程序(Windows Server 2003)。