夏令时和时区最佳做法

我希望将这个问题及其答案作为处理夏令时的权威性指南,特别是处理实际变更的过程。

如果你有任何补充,请做

许多系统都依赖于保持准确的时间,问题在于由于夏令时而改变时间 - 向前或向后移动时钟。

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

  • 你如何处理夏令时问题?
  • 什么假设是你的解决方案的一部分? (在这里寻找上下文)
  • 同样重要的是,如果不是如此:

  • 你做了什么没有奏效?
  • 为什么它不起作用?
  • 我会对编程,操作系统,数据持久性和其他相关问题感兴趣。

    一般的答案很好,但我也希望看到详细信息,特别是如果他们只在一个平台上可用。



    答案和其他数据摘要:(请加上你的)

    做:

  • 无论何时你指的是一个确切的时刻,根据一个不受夏时制影响的统一标准来坚持时间。 (GMT和UTC与此相同,但最好使用术语UTC。注意,UTC也被称为Zulu或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 for Java 8,或者使用Joda Time for Java 7或更低版​​本。
  • 如果使用.NET,请考虑使用Noda Time。
  • 如果在没有Noda Time的情况下使用.NET,请考虑DateTimeOffset通常是比DateTime更好的选择。
  • 如果使用Perl,请使用DateTime。
  • 如果使用Python,请使用pytz或dateutil。
  • 如果使用JavaScript,请使用带有时区延伸的moment.js。
  • 如果使用PHP> 5.2,请使用由DateTimeDateTimeZone类提供的本地时区转换。 使用DateTimeZone::listAbbreviations()时要小心 - 请参阅答案。 要使PHP保持最新的Olson数据,请定期安装timezonedb PECL包; 见答案。
  • 如果使用C ++,请确保使用正确实现IANA时区数据库的库。 这些包括cctz,ICU和Howard Hinnant的“tz”图书馆。
  • 不要使用Boost进行时区转换。 虽然其API声称支持标准IANA(又名“zoneinfo”)标识符,但它粗略地将其映射到POSIX样式的数据,而不考虑每个区域可能具有的丰富历史变化。 (此外,该文件已经不再维护。)
  • 大多数业务规则使用的是民用时间,而不是UTC或GMT。 因此,计划在应用应用程序逻辑之前将UTC时间戳转换为本地时区。
  • 请记住,时区和偏移量不固定,可能会改变。 例如,历史上美国和英国使用相同的日期来“前进”和“后退”。 但是,2007年美国改变了时钟变化的日期。 这意味着,一年中的48周,伦敦时间和纽约时间之间的差异为5小时,并且为4周(春季3次,秋季1次),这是4小时。 在任何涉及多个区域的计算中都要注意这样的项目。
  • 考虑时间类型(实际事件时间,广播时间,相对时间,历史时间,周期时间)需要存储哪些元素(时间戳,时区偏移和时区名称)以便正确检索 - 请参阅“时间类型”中的这个答案。
  • 让您的操作系统,数据库和应用程序数据文件在他们自己和世界其他地方之间保持同步。
  • 在服务器上,将硬件时钟和OS时钟设置为UTC而不是本地时区。
  • 无论以前的重点是什么,服务器端代码(包括网站)都不应该期望服务器的本地时区是特定的任何事物。 见答案。
  • 建议您在应用程序代码中逐个处理时区,而不是全局通过配置文件设置或默认值处理。
  • 在所有服务器上使用NTP服务。
  • 如果使用FAT32,请记住时间戳存储在本地时间,而不是UTC。
  • 在处理周期性事件(例如每周电视节目)时,请记住,时间随着DST而变化,并且在不同时区之间会有所不同。
  • 始终将日期 - 时间值查询为包含下限的上限排除( >=< )。
  • 别:

  • 不要将“时区”(如America/New_York与“时区偏移”(例如-05:00混淆。 他们是两个不同的东西。 查看时区标记wiki。
  • 请勿使用JavaScript的Date对象在较早的Web浏览器中执行日期和时间计算,因为ECMAScript 5.1及更低版本有可能错误地使用夏令时的设计缺陷。 (这在ECMAScript 6/2015中得到了修复)。
  • 永远不要相信客户的时钟。 这可能是不正确的。
  • 不要告诉人们“总是使用UTC”。 这个广泛的建议是本文前面描述的几种有效方案的短视。 相反,请为您正在使用的数据使用适当的时间参考。 (时间戳可以使用UTC,但未来的时间安排和仅限日期的值不应该)。
  • 测试:

  • 在测试时,确保你测试西,东,北,南半球的国家(事实上在全球的每个季度,所以有4个地区),DST正在进行而不是(提供8个),而一个国家不使用DST(另外4个覆盖所有地区,共计12个)。
  • 测试DST的转换,即当您目前处于夏季时,从冬季选择一个时间值。
  • 使用DST测试边界情况(例如UTC + 12的时区),使得夏季当地时间为UTC + 13,甚至冬季为UTC + 13的地方
  • 测试所有第三方库和应用程序,并确保它们正确处理时区数据。
  • 至少测试半小时时区。
  • 参考:

  • Stack Overflow上的详细timezone标签wiki页面
  • 奥尔森数据库,又名Tz_database
  • IETF起草维护Olson数据库的程序
  • 时区和DST的来源
  • ISO格式(ISO 8601)
  • 来自Unicode联盟的Olson数据库和Windows时区ID之间的映射
  • 时区页面上的维基百科
  • StackOverflow问题标记为dst
  • StackOverflow问题标记的timezone
  • 处理DST - Microsoft DateTime最佳实践
  • 网络时间协议维基百科
  • 其他:

  • 大厅你的代表结束可憎的是DST。 我们总是希望...
  • 地球标准时间大厅

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

    时代的类型

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

  • 活动时间:例如发生国际体育赛事的时间,或加冕/死亡等。 这取决于事件的时区而不是观众的时区。
  • 电视时间:例如,当地时间晚上9点在世界各地播放特定的电视节目。 在您的网站上发布结果(比如说美国偶像)时很重要
  • 相对时间:例如:这个问题在21小时内收到开放奖金。 这很容易显示
  • 经常性时间:例如:即使夏令时发生变化,电视节目也会在每周一晚上9点举行。
  • 还有历史/替代时间。 这些都很烦人,因为它们可能无法映射回标准时间。 例如:朱利安日期,根据土星农历,克林贡日历的日期。

    以UTC存储开始/结束时间戳效果很好。 对于1,您需要一个与事件一起存储的事件时区名称+偏移量。 对于2,您需要存储每个区域的本地时间标识符以及为每个查看器存储的本地时区名称+偏移量(如果您处于紧缩状态,可以从IP中获得此值)。 对于3,以UTC秒存储并且不需要时区。 4是1或2的特殊情况,具体取决于它是全局事件还是本地事件,但您还需要存储创建的时间戳,以便您可以确定在创建此事件之前或之后是否更改了时区定义。 如果您需要显示历史数据,这是必需的。

    储存时间

  • 始终以UTC存储时间
  • 转换为显示的本地时间(本地由查看数据的用户定义)
  • 存储时区时,需要名称,时间戳和偏移量。 这是必需的,因为政府有时会改变其时区的含义(例如:美国政府更改DST日期),并且您的应用程序需要优雅地处理事件......例如:DOST规则前后显示的确切时间戳改变。
  • 偏移和名称

    以上的例子是:

    足球世界杯决赛比赛于2010年7月11日19:00 UTC在南非(UTC + 2 - SAST)举行。

    有了这些信息,即使南非时区定义发生变化,我们也可以历史性地确定2010年WCS总决赛的确切时间, 并且能够在查询数据库时将其显示给当地时区的观众。

    系统时间

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

    确保硬件时钟设置为UTC,如果您在世界各地运行服务器,请确保其操作系统配置为使用UTC。 当您需要从多个时区中的服务器复制按小时轮播的apache日志文件时,这一点变得明显。 按文件名对它们进行排序仅适用于所有文件都使用相同时区命名的情况。 这也意味着,当你从一个盒子到另一个盒子并且需要比较时间戳时,你不必在脑中进行日期数学计算。

    另外,在所有盒子上运行ntpd。

    客户端

    永远不要相信您从客户端计算机获得的时间戳有效。 例如,Date:HTTP标头,或者一个javascript Date.getTime()调用。 当用作不透明标识符时,或者在同一客户端的单个会话期间进行日期数学计算时,这些都没有问题,但不要尝试将这些值与服务器上的某些值进行交叉引用。 您的客户不运行NTP,并且可能不需要为他们的BIOS时钟准备好工作电池。

    琐事

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

    荷兰标准时间从1909年5月1日至1937年6月30日,法定时间为19分钟32.13秒。 使用HH:MM格式无法准确表示此时区。

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


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

    从概念的角度来看,通常会处理两种类型的时间日期数据,并且便于区分它们(上述标准没有):“ 实际时间 ”和“ 公民时间 ”。

    “物理”时间瞬间是物理学处理的连续通用时间轴上的一个点(当然,忽略相对性)。 例如,如果您可以忽略闰秒,则可以对此概念进行充分编码 - 以UTC保存。

    “民间”时间是遵循民事规范的日期时间规范:此处的时间点由一组日期时间字段(Y,M,D,H,MM,S,FS)加上TZ(时区规范) (实际上也是“日历”,但让我们假设我们将讨论限制于公历)。 时区和日历共同允许(原则上)从一个表示映射到另一个表示。 但是,公民和物理时间刻度是根本不同类型的大小,应该保持它们在概念上的分离和不同的处理(类比:字节和字符串阵列)。

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

    约翰在他的日历中记录了2019-Jul-27, 10:30:00 TZ = Chile/Santiago日期时间的一些事件提示(它抵消了GMT-4,因此它对应于UTC 2019-Jul-27 14:30:00 )。 但是在未来的某一天,该国决定将TZ的偏移量改为GMT-5。

    现在,当一天到来...应该提醒触发

    A) 2019-Jul-27 10:30:00 Chile/Santiago = UTC time 2019-Jul-27 15:30:00

    要么

    B) 2019-Jul-27 9:30:00 Chile/Santiago = UTC time 2019-Jul-27 14:30:00

    没有正确的答案,除非人们知道约翰在讲日历时的概念意思“请在2019-Jul-27, 10:30:00 TZ=Chile/Santiago给我2019-Jul-27, 10:30:00 TZ=Chile/Santiago ”。

    他的意思是“公民日期时间”(“当我的城市的时钟告诉10:30”)? 在这种情况下,A)是正确的答案。

    还是他的意思是“物理时间瞬间”,即我们宇宙连续时间线中的一个点,比如说“下一次日食发生时”。 在这种情况下,答案B)是正确的。

    一些日期/时间API可以正确区分这个区别:其中包括Jodatime,它是下一个(第三个!)Java DateTime API(JSR 310)的基础。

    链接地址: http://www.djcxy.com/p/767.html

    上一篇: Daylight saving time and time zone best practices

    下一篇: How to insert an item into an array at a specific index?