datetime - 夏时制时间和时区的最佳实践

  显示原文与译文双语对照的内容

我希望把这个问题和它的答案确定为处理日光节约时间的决定性指南,特别是处理实际的更改结果。

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

许多系统依赖于保持精确的时间,问题是由于夏令时的变化而导致的时间变化- 将时钟向前或者向后移动。

例如一个有业务规则的顺序是依赖于订单时间的系统- 如果时钟改变,规则可能不那么清晰。 如何保持顺序的时间? 当然有无数的场景- 这只是一个说明性的例子。

  • 你如何处理夏令时问题?
  • 解决方案的一部分是什么假设? ( 在这里寻找上下文)

同样重要的是:

  • 你尝试了什么不工作?
  • 为什么它不起作用?

我对这个问题的编程,操作系统,数据持久性和其他相关方面感兴趣。

一般的回答很好,但我也想看到细节,尤其是在一个平台上。

时间:

我不确定我可以在上面的答案中添加什么,但这里有几个要点:

时间类型

你应该考虑四种不同的时间:

  1. 事件时间:例如发生国际运动事件的时间,或者 coronation/death/etc. 依赖于事件的时区而不是查看器。
  2. 电视时间:一个特定的电视节目在 下午9点 当地时间播出。 在你的网站上考虑发布结果( 比如说美国偶像) 时重要
  3. 相对时间:这个问题在 21小时内有一个开放的奖励关闭。 这很容易显示
  4. 重复时间:例如:电视放映在 9 pm的每星期一,甚至在DST改变时。

还有历史/交替时间。 这些很烦人,因为它们不能映射到标准时间。 例如:公历日期,根据土星的阴历历法,Klingon历法。

在UTC中存储开始/结束时间戳工作正常。 对于 1,你需要一个事件时区名称+ 偏移量随事件一起存储。 对于 2,需要存储每个区域的本地时间标识符和每个查看器( 如果你处于困境中,就可以从IP中导出它)的本地时区名称+ 偏移量。 对于 3,存储在UTC秒,不需要时区。 4是 1或者 2的特例,具体取决于它是全局事件还是局部事件,但你还需要存储一个时间戳,这样你就可以知道在这个事件之前或者之后是否已经更改了一个时区定义。 如果你需要显示历史数据,这是必要的。

存储时间

  • 总是以UTC存储时间
  • 在显示时转换为本地时间( 由用户在查看数据时定义)
  • 存储时区时,需要名称,时间戳和偏移量。 这是必需的,因为政府有时会改变他们时区的含义( 例如: govt更改了DST日期,你的应用程序需要正常处理。。 丢失的时间戳在DST规则改变前后的确切时间戳。

偏移量和名称

上面的示例是:

在在 19 2010年07月11日: 00 utc,足球世界杯的韵母游戏在小酒馆南非

当时他们用这个查询该database,信息时,我们可以将计算直线 2010韵母发生时你即使在历史上确定准确的时间时区定义更改,和南非能够显示那个面向观众在其本地 timezone.

系统时间

你还需要保持你的操作系统,数据库和应用程序tzdata文件彼此同步,同时与世界其他文件同步,并在你升级时广泛测试。 你所依赖的第三方应用程序没有正确处理TZ更改。

确保硬件时钟设置为 UTC,如果你在世界各地运行服务器,请确保它们的操作系统配置为使用 UTC 。 当你需要从多个时区的服务器复制每小时旋转的apache日志文件时,就变得显而易见了。 只有在所有文件都以相同的时区命名时,才能按文件名排序。 这也意味着当你从一个盒子到另一个盒子,并且需要比较时间戳时你不必在你的头脑中做日期数学。

同时,在所有框中运行 ntpd 。

客户端

从不信任从客户端机器获得的时间戳作为有效的时间戳。 例如日期:HTTP标头或者 javascript Date.getTime() 调用。 有你在server,上这些都是精细的对象时,作为不透明标识符,或者在进行日期数学在单个会话期间在上同一客户端,但不尝试cross-reference这些值 你的客户不运行 NTP,并且他们的BIOS时钟可能没有工作电池。

琐事

最后,政府有时会做一些奇怪的事情:

在荷兰时能够保证和 32.13 19分钟秒领先于中通过1909-05-01标准时间UTC通过 law. 这里时区不能用 HH:MM 格式精确表示。

好吧,我想我已经完成了。

越过"计算机时间"和"人们时间"的边界是一个噩梦。 主要的一个是,对于时区和夏令时的规则没有标准。 各国随时可以随意更改时区和DST规则,并且。

有些国家 比如,巴西每年决定每年的夏时制时间,所以在( 中频) DST生效时,无法提前知道。 其他的有 fixed(ish) 规则,当DST生效时。 其他国家不使用DST作为全部。

时区不一定要与GMT完全不同。 尼泊尔是 +5.45.甚至时区是 +13. 这意味着:


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

都是同一时间,但 3个不同的日子 !

在时区的缩写上还没有明确的标准,以及它们在DST中的变化情况,因此你最终会得到这样的结果:


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

最好的建议是尽可能远离本地时间,并坚持 UTC,在那里你可以。 只在最后可能的时刻转换为本地时间。

当测试时,请确保你在西部和东部的国家和地区测试国家和地区,同时没有使用 DST ( 总共 6 )的国家和地区。

虽然我没有尝试过,我觉得一种方法要时区调整我会感兴趣可以将为:

  1. 以UTC存储所有内容。

  2. 创建包含三列的表 TZOffsets: RegionClassId,StartDateTime和 OffsetMinutes ( int,分钟) 。

在表中,存储日期和时间的本地时间当及其活跃程度更改的列表。 表格中区域的数量和日期的数量取决于你需要支持的日期和区域的范围。 认为这是"历史"日期,即使日期应该包含未来的一些实际限制。

当需要计算任何UTC时间的本地时间时,只需执行以下操作:


SELECT DATEADD('m', SUM(OffsetMinutes), @inputdatetime) AS LocalDateTime
FROM TZOffsets
WHERE StartDateTime <= @inputdatetime
 AND RegionClassId = @RegionClassId;

你可能想要在你的应用程序中缓存这个表,并使用LINQ或者一些类似的方法来执行查询,而不是点击数据库。

这些数据可以从公共域数据库中提取

这里方法的优点和脚注:

  1. 代码中没有烘焙规则,你可以调整新区域或者日期范围的偏移量。
  2. 你不必支持每个日期或者区域的范围,你可以根据需要添加它们。
  3. 区域不需要直接对应于地缘政治边界,为了避免重复行( 例如美国的大多数州都以同样的方式处理 DST ),你可以在另一个表中使用大量的RegionClass条目链接到更传统的状态lists国家或者地区列表。
  4. 对于像美国这样的情况,在过去几年中,DST的开始和结束日期已经改变,这很容易处理。
  5. 因为StartDateTime字段可以存储时间,所以 2: 00的标准change-over时间很容易处理。
  6. 世界上并非处处使用 1 -hour DST 。 这很容易处理这些情况。
  7. 数据表是 cross-platform,可以是一个单独的open-source项目,它可以被使用几乎任何数据库平台或者编程语言的开发人员使用。
  8. 这可以用于与时区无关的偏移量。 例如 1 -second调整,随时调整地球自转,历史调整和公历等。
  9. 由于这是在数据库表,标准报告查询中,等等 可以利用数据而不用通过业务逻辑代码。
  10. 这也处理时区偏移量,如果你想这样做,甚至可以将一个区域分配给另一个时区的特殊历史情况。 你所需要的是一个初始日期,它为每个区域分配一个最小开始日期的时区偏移。 这需要为每个时区创建至少一个区域,但允许你询问以下有趣问题: 在 5: 00am"Yuma,亚利桑那州和西雅图,华盛顿在2 月 2之间用本地时间有什么区别?

现在,唯一的缺点是这种方法或者任何其他 。从 本地时间转换为GMT并不是完美的,因为任何的夏令时改变这种情况,有一个负的偏移到时钟重复给定的本地时间。 没有简单的方法来处理这个问题,我害怕,存储本地时间是一个不好的消息。

如果你的设计能容纳它,那么可以避免本地时间转换 !

我知道这听起来有些疯狂,但考虑一下用户界面: 用户进程接近,相对日期( 今天,昨天,下星期一) 比绝对日期( 2010.09.17,周五月9 日) 快( glance ) 。 所以当你考虑它更多,知道多个时区中的准确性( 和 DST ) 更重要是为了 now()的日期越接近,所以如果你可以表达为+/- 日期/datetimes在相对比较格式 1或者 2周,其余的日期能够UTC和事情不会物质上 95%有些过分的用户。

通过这种方式,你可以用UTC存储所有日期,并在UTC中进行相对比较,只在相对日期阈值之外显示用户的UTC日期。

这也可以应用到用户输入( ( 但通常以一种更有限的方式) ) 。 从下拉列表中选择 { 昨天,今天,明天,下星期一,下周四的} 比日期选择器更简单更容易。 日期选择器是构成表单填充的最痛苦的部分。 当然这对所有的情况都不起作用,但是你可以看到,它只需要一些巧妙的设计来使它非常强大。

...