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

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

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

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

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

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

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

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

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


当前回答

以下是我的经验:-

(不需要任何第三方库)

在服务器端,以UTC格式存储时间,以便数据库中的所有日期/时间值都采用单一标准,而不考虑用户、服务器、时区或DST的位置。在UI层或发送给用户的电子邮件中,您需要根据用户显示时间。为此,您需要有用户的时区偏移量,以便将此偏移量添加到数据库的UTC值中,这将导致用户的本地时间。您可以在用户注册时获取他们的时区偏移,也可以在web和移动平台中自动检测他们。对于网站,JavaScript的函数getTimezoneOffset()方法是1.0版以来的标准,并且与所有浏览器兼容。(参考:http://www.w3schools.com/jsref/jsref_getTimezoneOffset.asp)

其他回答

我不知道我能为上面的答案补充什么,但我有几点:

时间类型

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

事件时间:例如,国际体育赛事发生的时间,或加冕/死亡等。这取决于事件的时区,而不是观众的时区。电视时间:例如,一个特定的电视节目在世界各地的当地时间晚上9点播出。当考虑在你的网站上发布(比如美国偶像)结果时,这一点很重要相对时间:例如:这个问题将在21小时内结束。这很容易显示重复播放时间:例如:每周一晚上9点播放电视节目,即使夏令时改变。

还有历史/备用时间。这些都很烦人,因为它们可能无法映射回标准时间。例如:朱利安日期,根据土星的阴历,克林贡日历。

在UTC中存储开始/结束时间戳效果良好。对于1,您需要与事件一起存储事件时区名称+偏移量。对于2,您需要为每个区域存储一个本地时间标识符,并为每个观众存储一个当地时区名称+偏移量(如果您遇到困难,可以从IP中导出)。对于3,以UTC秒存储,不需要时区。4是1或2的特殊情况,这取决于它是全局事件还是本地事件,但您还需要存储在时间戳创建的,以便您可以判断在创建此事件之前或之后是否更改了时区定义。如果需要显示历史数据,这是必要的。

存储时间

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

偏移和名称

上述示例如下:

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

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

系统时间

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

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

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

客户

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

琐事

最后,政府有时会做出非常奇怪的事情:

荷兰的标准时间是正好19分32.13秒在1909-05-01年法律规定的UTC之前通过1937-06-30。此时区不能使用HH:MM格式。

好的,我想我完了。

您需要了解Olson-tz数据库,可从ftp://elsie.nci.nih.gov/pub http://iana.org/time-zones/.它每年更新多次,以应对世界各地不同国家在冬季和夏季(标准时间和夏令时)之间切换的时间(以及是否切换)的最后时刻变化。2009年,最后一次发布是2009年;2010年为2010n;2011年为2011n;2012年5月底,发布时间为2012c。注意,在两个独立的存档(tzcode20xxy.tar.gz和tzdata20xxy.tar.gz)中有一组代码来管理数据和实际时区数据本身。代码和数据都在公共域中。

这是时区名称的来源,如America/Los_Angeles(和同义词,如US/Pacific)。

如果你需要跟踪不同的区域,那么你需要奥尔森数据库。正如其他人所建议的,您还希望以固定格式(UTC通常是所选的格式)存储数据,并记录生成数据的时区。您可能需要区分时间与UTC的偏移量和时区名称;这会在以后产生影响。此外,知道当前是2010-03-28T23:47:00-07:00(美国/太平洋)可能会或可能不会帮助您解释值2010-11-15T12:30-这可能是在PST(太平洋标准时间)而不是PDT(太平洋夏令时)中指定的。

标准的C库接口对这类东西没有太大的帮助。


奥尔森的数据发生了变化,部分原因是A·D·奥尔森很快就要退休了,另一部分原因是对维护者的版权侵权诉讼(现已驳回)。时区数据库现在由互联网号码分配机构IANA负责管理,并且在首页有一个“时区数据库”链接。讨论邮件列表现在是tz@iana.org; 公告列表是tz-announce@iana.org.

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

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

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

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

永远不要在没有UTC偏移(或时区参考)的情况下存储本地时间-如何不这样做的示例包括C¹中的FAT32和结构tm了解时区是一组UTC偏移(例如,冬季+0100,夏季+0200)切换发生的时间规则(可能会随着时间的推移而改变:例如,在20世纪90年代,欧盟将切换统一为3月和10月的最后一个星期日,标准时间02:00/夏令时03:00;之前成员国之间有所不同)。


¹struct tm的一些实现确实存储UTC偏移量,但这并未将其纳入标准。

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

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

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

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

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

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