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

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

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

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

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

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

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

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

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


当前回答

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

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这一令人厌恶的行为。我们总是希望。。。地球标准时间大厅

其他回答

永远不要只依赖像这样的构造函数

 new DateTime(int year, int month, int day, int hour, int minute, TimeZone timezone)

当某个日期时间由于DST而不存在时,它们可以抛出异常。相反,构建自己的方法来创建这样的日期。在它们中,捕捉由于DST而发生的任何异常,并使用转换偏移调整所需的时间。根据时区,夏令时可能会在不同的日期和时间(甚至巴西的午夜)发生。

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

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

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

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

将服务器设置为UTC,并确保所有服务器都配置为ntp或同等版本。

UTC避免了夏令时问题,服务器不同步可能会导致不可预测的结果,需要一段时间才能进行诊断。

我最近在一个web应用程序中遇到了一个问题,在Ajax帖子中,返回到服务器端代码的日期时间与提供的日期时间不同。

这很可能与我在客户端上的JavaScript代码有关,该代码建立了以字符串形式发送回客户端的日期,因为JavaScript正在调整时区和夏时制,在某些浏览器中,何时应用夏时制的计算似乎与其他浏览器不同。

最后,我选择完全删除客户端上的日期和时间计算,并在一个整数键上返回到服务器,然后在服务器上转换为日期时间,以实现一致的转换。

我从中学习到:除非绝对必须,否则不要在web应用程序中使用JavaScript日期和时间计算。

实际上,kernel32.dll不导出SystemTimeToTzSpecificLocation。但是,它确实导出以下两个:SystemTimeToTzSpecificLocalTime和TzSpecificLocalTimeToSystemTime。。。