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

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

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

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

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

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

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

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

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


当前回答

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

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

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

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

其他回答

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();
?>

跨越“计算机时间”和“人类时间”的界限是一场噩梦。主要原因是,时区和夏令时的规则没有一种标准。各国可以随时自由更改时区和夏令时规则,他们也可以这样做。

一些国家,例如以色列、巴西,每年都会决定何时实行夏令时,因此无法提前知道夏令时何时生效。其他人对DST何时生效有固定的规则。其他国家并不完全使用夏令时。

时区不必与格林尼治标准时间相差整整一小时。尼泊尔为+5.45。甚至还有+13的时区。这意味着:

SUN 23:00 in Howland Island (-12)
MON 11:00 GMT 
TUE 00:00 in Tonga (+13)

都是同一时间,但3天不同!

对于时区的缩写,以及它们在夏令时中的变化,也没有明确的标准,因此您最终会遇到这样的情况:

AST Arab Standard Time     UTC+03
AST Arabian Standard Time  UTC+04
AST Arabic Standard Time   UTC+03

最好的建议是尽可能远离当地时间,尽可能坚持UTC。仅在最后一刻转换为当地时间。

测试时,请确保您测试了西半球和东半球的国家,其中既有正在进行的夏令时,也有未使用夏令时的国家(共6个)。

您正在使用.NET框架吗?如果是这样的话,让我向您介绍一下与.NET3.5一起添加的DateTimeOffset类型。

此结构同时包含DateTime和Offset(TimeSpan),后者指定DateTimeOffset实例的日期和时间与协调世界时(UTC)之间的差异。

DateTimeOffset.Now静态方法将返回DateTimeOffset由当前(本地)时间和本地偏移组成的实例(如操作系统的区域信息中所定义)。DateTimeOffset.UtcNow静态方法将返回DateTimeOffset实例包含UTC中的当前时间(如如果你在格林威治)。

其他有用的类型是TimeZone和TimeZoneInfo类。

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

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

对于网络来说,规则没有那么复杂。。。

服务器端,使用UTC客户端,使用Olson原因:UTC偏移量不是夏令时安全的(例如,纽约是一年中的EST(UTC-5小时)部分,EDT(UTC-4小时)部分)。对于客户端时区确定,您有两个选项:1) 用户设置区域(更安全)资源:Web就绪的Olson-tz HTML下拉列表和JSON2) 自动检测区域资源:jsTimezoneDetect

剩下的只是使用服务器端日期时间库进行UTC/本地转换。很好去。。。