夏令时和时区最佳实践

本文探讨了处理夏令时和时区问题的挑战,强调了使用UTC作为统一时间标准的重要性。建议避免依赖可能导致异常的系统日期时间处理,而应构建自定义方法来处理DST变化。推荐使用Olson时区数据库以获取最新的时区信息,并在存储时间戳时考虑UTC和本地时间偏移。文章还讨论了不同编程语言和平台的解决方案,如PHP的时区处理问题,以及在数据库中正确存储和转换时间的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我希望使这个问题及其答案成为处理夏时制(尤其是处理实际变更)的权威指南。

如果您要添加任何内容,请执行

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

例如,一个在接订单系统中有取决于订单时间的业务规则-如果时钟改变,则规则可能不太清楚。 订购时间应如何保留? 当然,有无数种情况-这只是一种说明。

  • 您如何处理夏令时问题?
  • 解决方案中包含哪些假设? (在此处查找上下文)

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

  • 您尝试了什么却不起作用?
  • 为什么不起作用?

我会对编程,操作系统,数据持久性以及该问题的其他相关方面感兴趣。

一般的答案很好,但是我也想看看细节,特别是如果它们仅在一个平台上可用。


#1楼

永远不要只依赖像

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

当由于DST导致某个日期时间不存在时,它们可以引发异常。 相反,应构建自己的方法来创建此类日期。 在它们中,捕获由于DST发生的所有异常,并需要用转换偏移量调整时间。 DST可能会在不同的日期和不同的时间(对于巴西甚至在午夜)发生。


#2楼

对于网络而言,规则并不那么复杂...

  • 服务器端,使用UTC
  • 客户端,使用Olson
    • 原因:UTC偏移不是夏令时安全的(例如,纽约是一年中的EST(UTC-5小时),一年中其余时间是EDT(UTC-4小时))。
    • 对于客户端时区确定,您有两个选择:

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


#3楼

对于那些在.NET上苦苦挣扎的人,请参阅使用DateTimeOffset和/或TimeZoneInfo是否值得一试。

如果您想使用IANA / Olson时区 ,或者发现内置类型不足以满足您的需求,请查看Noda Time ,它为.NET提供了更智能的日期和时间API。


#4楼

PHP的DateTimeZone::listAbbreviations()输出

此PHP方法返回一个包含一些“主要”时区(例如CEST)的关联数组,这些时区本身包含更特定的“地理”时区(例如欧洲/阿姆斯特丹)。

如果您正在使用这些时区及其偏移量/ DST信息,那么实现以下内容非常重要:

似乎每个时区的所有不同偏移量/ DST配置 (包括历史配置)都包括在内!

例如,在此函数的输出中可以找到六次欧洲/阿姆斯特丹。 直到1937年为止的阿姆斯特丹时间都有两次出现(偏移1172/4772); 其中两个(1200/4800)用于1937年至1940年之间的时间; 和两个(3600/4800)是自1940年以来使用的时间。

因此, 您不能依赖此函数当前正确/正在使用的偏移/ DST信息

如果您想知道某个时区的当前偏移/ DST,则必须执行以下操作:

<?php
$now = new DateTime(null, new DateTimeZone('Europe/Amsterdam'));
echo $now->getOffset();
?>

#5楼

业务规则应始终在民事时间生效 (除非法律另有规定)。 请注意,民事时间是一团糟,但这是人们所使用的,所以这很重要。

在内部,将时间戳记保持为距民用时间秒数之类的时间。 纪元并不重要(我更喜欢Unix纪元 ),但确实比其他事情容易。 假装leap秒根本就不存在,除非您正在做某些真正需要leap秒的事情(例如,卫星跟踪)。 时间戳和显示时间之间的映射是应该应用DST规则的唯一点; 规则经常更改(在全球范围内,每年几次;指责政客),因此您应确保不对映射进行硬编码。 奥尔森的TZ数据库非常宝贵。


#6楼

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

做:

  • 每当您指的是确切的时间时,请按照不受夏令时影响的统一标准坚持时间。 (GMT和UTC在这方面是等效的,但最好使用术语UTC。请注意,UTC也称为ZuluZ time。)
  • 如果相反,您选择使用本地时间值来保留时间,则包括该特定时间与UTC的本地时间偏移量(此偏移量可能会在全年中发生变化),以便以后可以明确地解释时间戳。
  • 在某些情况下,你可能需要同时存储UTC时间和等效本地时间。 通常,这是通过两个单独的字段完成的,但是某些平台支持可以将两个字段都存储在一个字段中的datetimeoffset类型。
  • 将时间戳记存储为数值时,请使用Unix时间 -这是自1970-01-01T00:00:00Z以来的秒数(不包括leap秒)。 如果需要更高的精度,请改用毫秒。 此值应始终基于UTC,而无需进行任何时区调整。
  • 如果以后可能需要修改时间戳,请包括原始时区ID,以便可以确定偏移量是否可能与记录的原始值有所变化。
  • 在安排未来事件时,通常首选本地时间而不是UTC,因为偏移通常会发生变化。 请参阅答案博客文章
  • 当存储整个日期(例如生日和周年纪念日)时,请勿转换为UTC或任何其他时区。
    • 如果可能,以不包括一天中的时间的仅日期数据类型存储。
    • 如果没有这样的类型,则在解释该值时请确保始终忽略时间。 如果您不能确定一天中的时间会被忽略,请选择中午12:00,而不是午夜00:00,作为该天更安全的代表时间。
  • 请记住,时区偏移量并非始终是整数小时(例如,印度标准时间为UTC + 05:30,而尼泊尔使用UTC + 05:45)。
  • 如果使用Java, 则将Java.time用于Java 8及更高版本。
  • 如果使用.NET ,请考虑使用Noda Time
  • 如果使用不带Noda Time的.NET,请考虑使用DateTimeOffset通常比DateTime更好。
  • 如果使用Perl,请使用DateTime
  • 如果使用Python,请使用pytzdateutil
  • 如果使用JavaScript,请使用带有moment-timezone扩展名的moment.js
  • 如果使用PHP> 5.2,请使用DateTimeDateTimeZone类提供的本地时区转换。 使用DateTimeZone::listAbbreviations()时要小心- 参见answer 。 为了使PHP具有最新的Olson数据,请定期安装timezonedb PECL软件包; 看答案
  • 如果使用C ++,请确保使用使用正确实现IANA时区数据库的库 。 这些包括cctzICUHoward Hinnant的“ tz”库
    • 不要将Boost用于时区转换。 尽管其API声称支持标准IANA(又名“ zoneinfo”)标识符,但它粗略地将它们映射到POSIX样式的数据,而无需考虑每个区域可能具有的丰富变更历史。 (此外,该文件已退出维护。)
  • 如果使用Rust,请使用chrono
  • 大多数业务规则使用民事时间,而不是UTC或GMT。 因此,在应用逻辑之前,计划将UTC时间戳转换为本地时区。
  • 请记住,时区和偏移量不是固定的,可能会发生变化。 例如,从历史上看,美国和英国使用相同的日期来“向前跳”和“向后退”。 但是,在2007年,美国更改了更改时钟的日期。 现在,这意味着一年中的48周,伦敦时间和纽约时间之间的时差为5小时,而4周(春季为3个,秋季为1个)为4小时。 在涉及多个区域的任何计算中,请注意此类项目。
  • 考虑时间类型(实际事件时间,广播时间,相对时间,历史时间,重复发生的时间),您需要存储哪些元素(时间戳,时区偏移量和时区名称)以进行正确检索-请参阅“时间类型” 这个答案
  • 在您自己的OS,数据库和应用程序tzdata文件之间以及与世界其他地方之间保持同步。
  • 在服务器上,将硬件时钟和操作系统时钟设置为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的地方
  • 测试所有第三方库和应用程序,并确保它们正确处理时区数据。
  • 至少测试半小时时区。

参考:

其他:

  • 游说您的代表以终止DST的可憎之处。 我们总是可以希望...
  • 地球标准时间大厅

#7楼

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

这很可能与我在客户端上的JavaScript代码有关,该代码确定了以字符串形式发布回客户端的日期,因为JavaScript会针对时区和夏令时进行调整,并且在某些浏览器中会计算何时应用夏令时。似乎与其他人有所不同。

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

我的经验教训:除非绝对必要,否则请不要在Web应用程序中使用JavaScript日期和时间计算。


#8楼

将您的服务器设置为UTC,并确保将它们都配置为ntp或同等功能。

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


#9楼

我在两种类型的系统上都做到了这一点:“轮班计划系统(例如工厂工人)”和“天然气依赖管理系统”…

每天23到25个小时的工作很痛苦,所以8个小时的轮班需要7个小时或9个小时。 问题是您会发现每个客户,甚至客户部门对于他们在这些特殊情况下的操作都创建了不同的规则(通常没有文档记录)。

最好在客户购买“现成”软件后再问客户一些问题。 很少有客户在购买软件时就事先考虑过此类问题。

我认为在所有情况下,您都应该以UTC格式记录时间,并在存储日期/时间之前将时间转换为本地时间。 但是,即使使用夏令时和时区也很难知道给定时间在哪。


#10楼

通常,在存储的时间戳中包括本地时间偏移(包括DST偏移) :如果您以后要在其原始时区(和DST设置)中显示时间戳,仅使用UTC是不够的。

请记住,偏移量并非始终是整数小时(例如,印度标准时间为UTC + 05:30)。

例如,合适的格式是元组(unix时间,以分钟为单位的偏移量)或ISO 8601


#11楼

虽然我还没有尝试过,但我发现令人信服的时区调整方法如下:

  1. 将所有内容存储在UTC中。

  2. 用三列创建表TZOffsets :RegionClassId,StartDateTime和OffsetMinutes(整数,以分钟为单位)。

在表中,存储当地时间更改的日期和时间列表以及更改的时间。 表中的区域数和日期数将取决于您需要支持的日期范围和世界范围。 即使日期应该包括将来的某个实际限制,也可以将其视为“历史”日期。

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

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

您可能希望将此表缓存在您的应用程序中,并使用LINQ或其他类似方法进行查询,而不是访问数据库。

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

此方法的优点和脚注:

  1. 没有规则融入代码中,您可以轻松调整新区域或日期范围的偏移量。
  2. 您不必支持所有日期或区域范围,可以根据需要添加它们。
  3. 区域不必直接对应于地缘政治边界,并且为了避免重复行(例如,美国的大多数州以相同的方式处理DST),您可以具有广泛的RegionClass条目,这些条目在另一个表中链接到更传统的列表州,国家等
  4. 对于美国这样的情况,在过去几年中,夏令时的开始和结束日期已发生变化,这很容易处理。
  5. 由于StartDateTime字段也可以存储时间,因此可以轻松处理2:00 AM标准转换时间。
  6. 世界上并非每个地方都使用1小时DST。 这样可以轻松处理这些情况。
  7. 数据表是跨平台的,可以是一个单独的开源项目,几乎使用任何数据库平台或编程语言的开发人员都可以使用。
  8. 这可用于与时区无关的偏移量。 例如,不时进行1秒调整以适应地球的自转,对公历及其内部的历史调整等。
  9. 由于这是在数据库表中,因此标准报表查询等可以利用数据,而无需花费业务逻辑代码。
  10. 如果需要,它也可以处理时区偏移,甚至可以考虑将区域分配给另一个时区的特殊历史情况。 您所需要的只是一个初始日期,该日期以最小的开始日期为每个区域分配时区偏移量。 这将需要为每个时区创建至少一个区域,但是您可以提出一些有趣的问题,例如:“ 1989年2月2日凌晨5:00,亚利桑那州尤马市和华盛顿州西雅图市之间的当地时间有何不同?” (只需从另一个中减去一个SUM())。

现在,这种方法或其他方法的唯一缺点是本地时间到GMT的转换并不完美,因为任何对时钟有负偏移的DST更改都会重复给定的本地时间。 恐怕没有简单的方法可以解决这个问题,这是首先存储本地时间是坏消息的原因。


#12楼

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

从概念的角度来看,通常处理两种类型的时间日期数据,并且很容易区分它们(上述标准没有):“ 物理时间 ”和“ 民事时间 ”。

时间的“物理”时刻是物理处理的连续通用时间线中的一个点(当然,忽略相对论)。 例如,此概念可以在UTC中进行适当的编码持久化(如果您可以忽略leap秒)。

“民事”时间是遵循民事规范的日期时间规范:此处的时间点由一组日期时间字段(Y,M,D,H,MM,S,FS)加上TZ(时区规范)完全指定(实际上,这也是一个“日历”;但假设我们将讨论范围限制为公历)。 时区和日历共同(原则上)允许从一种表示映射到另一种表示。 但是民用和物理时刻在根本上是不同的量值类型,应该在概念上将它们保持分开并以不同的方式对待(类比:字节和字符串数组)。

这个问题令人困惑,因为我们可以互换地谈论这些类型的事件,并且因为平民时代可能会发生政治变化。 对于将来的事件,问题(以及区分这些概念的需求)变得更加明显。 示例(摘自我在这里的讨论。

John在他的日历中记录了日期为2019-Jul-27, 10:30:00 TZ的某些事件的提醒,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给我打电话”时的概念含义。

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

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

一些Date / Time API可以正确地实现这种区分:其中有Jodatime ,它是下一个(第三个!)Java DateTime API(JSR 310)的基础。


#13楼

如果您碰巧维护了运行DST的数据库系统,请仔细检查在秋季过渡期间是否需要关闭它们。 Mandy DBS(或其他系统)不喜欢在(本地)时间两次传递相同的点,这恰恰是您在秋天倒转时钟时会发生的情况。 SAP通过(IMHO真正整洁)的解决方案解决了这一问题-他们没有回退时钟,而是让内部时钟以正常速度的一半运行了两个小时...


#14楼

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

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

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

标准的C库接口对于此类工作不是很有帮助。


奥尔森(Olson)的数据有所变化,部分原因是公元奥尔森(AD Olson)即将退休,部分原因是针对维护者的版权侵权提起了诉讼(现已撤销)。 现在,时区数据库是在IANA (互联网分配号码管理局)的主持下管理的,并且首页上有一个指向“时区数据库”的链接 。 现在,讨论邮件列表为tz@iana.org ; 公告列表是tz-announce@iana.org


#15楼

跨越“计算机时间”和“人员时间”的界限是一场噩梦。 主要的问题是,关于时区和夏令时的规则没有任何标准。 各国可以随时自由更改其时区和夏令时规则。

一些国家(例如以色列,巴西)每年决定何时设置夏令时,因此无法预先知道夏令时的生效时间。 其他人对DST生效时间有固定的(ish)规则。 其他国家并没有全部使用DST。

时区不必与格林尼治标准时间整整一小时。 尼泊尔为+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,也没有进行的DST)以及未使用DST的国家(总计6个)。


#16楼

这是我的经验:

(不需要任何第三方库)

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

#17楼

对于在服务器上运行的应用程序(包括网站和其他后端服务),应用程序应忽略服务器的时区设置。

常见建议是将服务器的时区设置为UTC。 这确实是一个很好的最佳实践,但是它可以作为不遵循其他最佳实践的应用程序的创可贴。 例如,服务可能正在写入具有本地时间戳而不是基于UTC的时间戳的日志文件,从而在夏时制回退过渡期间造成歧义。 将服务器的时区设置为UTC将修复应用程序。 但是,真正的解决方法是使应用程序首先使用UTC进行记录。

服务器端代码(包括网站) 绝对不能期望服务器的本地时区特别重要。

在某些语言中,本地时区可以轻松爬入应用程序代码。 例如,.NET中的DateTime.ToUniversalTime方法将从本地时区转换为UTC,并且DateTime.Now属性返回本地时区中的当前时间。 另外,JavaScript中的Date构造函数使用计算机的本地时区。 还有很多其他这样的例子。 重要的是练习防御性编程,避免使用计算机本地时区设置的任何代码。

使用本地时区保留客户端代码,例如桌面应用程序,移动应用程序和客户端JavaScript。


#18楼

我不确定我可以在上面的答案中添加什么,但是我有几点建议:

时间类型

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

  1. 活动时间:例如,国际体育赛事发生的时间或加冕/死亡/等时间。 这取决于事件的时区,而不取决于查看器。
  2. 电视时间:例如,某个特定的电视节目在世界各地的当地时间晚上9点播出。 考虑在您的网站上发布结果(例如“美国偶像”)时很重要
  3. 相对时间:例如:此问题在21小时内有悬空赏金。 这很容易显示
  4. 循环播放时间:例如:即使DST更改,电视节目也每周星期一晚上9点播放。

也有历史/备用时间。 这些很烦人,因为它们可能无法映射回标准时间。 例如:朱利安(Julian)日期,根据土星(Klingon)日历上的阴历确定日期。

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

储存时间

  • 始终将时间存储在UTC中
  • 转换为显示的本地时间(本地由用户查看数据定义)
  • 存储时区时,您需要名称,时间戳和偏移量。 这是必需的,因为政府有时会更改其时区的含义(例如:美国政府更改了夏令时的日期),并且您的应用程序需要妥善处理……例如:当DOST规则前后都显示LOST情节的确切时间戳改变了。

偏移量和名称

以上是一个示例:

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

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

系统时间

您还需要使您的OS,数据库和应用程序tzdata文件相互之间以及与世界其他地方保持同步,并在升级时进行广泛的测试。 您依赖的第三方应用未正确处理TZ更改并非闻所未闻。

确保硬件时钟设置为UTC,并且如果您在世界各地运行服务器,请确保其操作系统也配置为使用UTC。 当您需要从多个时区的服务器复制每小时轮换的apache日志文件时,这变得显而易见。 仅当所有文件都使用相同的时区命名时,才按文件名对它们进行排序。 这也意味着,当您从一个框切换到另一个框并需要比较时间戳时,您不必费心地进行日期数学运算。

另外,在所有机器上运行ntpd。

客户群

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

琐事

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

从1909-05-01到1937-06-30,根据法律,荷兰的标准时间恰好比UTC提前19分32.13秒。 无法使用HH:MM格式准确表示该时区。

好吧,我想我完成了。


#19楼

明确关注点的架构分离-要确切知道与用户交互的层,并且必须更改规范表示(UTC)的日期/时间。 非UTC日期时间是表示形式 (遵循用户本地时区), UTC时间是模型 (后端和中间层保持唯一)。

另外,请确定您的实际受众是什么,您不必为什么服务以及在哪里划界 。 除非您在那里确实有重要的客户,然后再考虑仅用于该地区的面向用户的服务器,否则请勿触摸异国日历。

如果您可以获取并维护用户的位置,请使用位置进行系统的日期时间转换(例如.NET文化或SQL表),但如果日期时间对用户至关重要,则可以为最终用户提供替代方法。

如果涉及历史审计义务 (例如准确说出AZ的Jo在2年前于9月支付帐单的时间 ), 则同时保留UTC和本地时间作为记录(您的转换表将随时间变化)。

为大量数据定义时间参考时区 (例如文件,Web服务等)。说东海岸公司在CA设有数据中心-您需要询问并知道它们用作标准的内容,而不是假设一个或另一个。

不要相信嵌入在日期时间文本表示形式中的时区偏移量,也不接受解析和跟踪它们。 而是始终要求必须明确定义时区和/或参考区 。 您可以轻松接收带有PST偏移量的时间,但是该时间实际上是EST,因为这是客户端的参考时间,并且记录只是在PST中的服务器上导出的。


#20楼

另一件事,请确保服务器已应用了最新的夏令时补丁。

去年,我们遇到了一种情况,即使我们使用的是基于UTC的系统,北美用户在三个星期的时间里也始终保持一小时的时间。

最终结果是服务器。 他们只需要应用最新的补丁程序( Windows Server 2003 )。


#21楼

处理FAT32文件系统中存储的时间戳时要小心-它始终保存在本地时间坐标中(包括DST-请参见msdn article )。 被烧死了。


#22楼

汤姆·斯科特(Tom Scott)在Computerphile频道上的YouTube时区视频中 ,也对该主题进行了生动有趣的描述。 示例包括:

  • 萨摩亚 (太平洋中的一个岛屿)将时区向前移动了24小时,以简化与澳大利亚和新西兰的贸易,
  • 西岸(West Bank) ,有2个人在不同的时区,
  • 18世纪从儒略历转变为公历 (发生在20世纪的俄罗斯)。

#23楼

如果您的设计可以容纳它,请避免一起进行本地时间转换!

我知道有些听上去很疯狂,但考虑到UX:用户一眼就能看到,相对日期(今天,昨天,下周一)的处理时间比绝对日期(2010.09.17,9月17日,星期五)要快。 而且,当您考虑得更多时,时区(和DST)的准确性越接近日期,就越重要now()因此now() ,因此,如果您可以用+/- 1或2周的相对格式来表示日期/日期时间,其余日期可以是UTC,对于95%的用户而言,它并不重要。

这样,您可以将所有日期存储在UTC中,并在UTC中进行相对比较,并且只需在相对日期阈值之外显示用户UTC日期即可。

这也可以应用于用户输入(但通常以更有限的方式)。 从一个只有{昨天,今天,明天,下一个星期一,下一个星期四}的下拉列表中进行选择,对用户而言,比日期选择器要简单得多。 日期选择器是表单填充中最容易引起疼痛的部分。 当然,这并非在所有情况下都适用,但是您可以看到,仅需一点点巧妙的设计就可以使其非常强大。


#24楼

仅举一个例子就可以证明,处理时间是所描述的巨大混乱,并且您永远不能沾沾自喜。 在此页面上的几个地方,leap秒已被忽略。

几年前,Android操作系统使用GPS卫星获取UTC时间参考,但忽略了GPS卫星不使用leap秒的事实。 直到除夕出现混乱时,没人注意到,当时苹果手机用户和安卓手机用户的倒计时大约相差15秒。

我认为此问题已得到解决,但您永远不知道这些“次要细节”何时会再次困扰您。


#25楼

  • 永远不要存放没有它的UTC偏移本地时间(或时区的引用)FAT32如何不去做它包括-examples和struct tm在C.¹
  • 了解时区是以下各项的组合
    • 一组UTC偏移量(例如,冬天+0100,夏天+0200)
    • 切换发生时间的规则(可能会随时间而变化:例如,在1990年代,欧盟将切换协调为3月和10月的最后一个星期日,标准时间02:00 / DST 03:00;以前是不同的成员国之间)。

¹struct struct tm某些实现确实存储UTC偏移量,但这尚未成为标准。


#26楼

对于PHP:

PHP> 5.2中的DateTimeZone类已经基于其他人提到的Olson数据库,因此,如果您在PHP中而不是在DB中进行时区转换,则可以免于使用(难以理解的)Olson文件。

但是,PHP的更新频率不如Olson DB那样频繁,因此仅使用PHP的时区转换可能会给您带来过时的DST信息,并影响数据的正确性。 尽管这种情况不会经常发生,但可能会发生,并且如果您在全球拥有大量用户,则可能发生。

要解决上述问题,请使用timezonedb pecl包 。 它的功能是更新PHP的时区数据。 请在更新后频繁安装此软件包。 (我不确定此软件包的更新是否完全跟在Olson更新之后,但是似乎更新的频率至少与Olson更新的频率非常接近。)


#27楼

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


#28楼

只是想指出似乎不正确或至少令人困惑的两件事:

始终按照不受夏时制影响的统一标准坚持时间。 尽管UTC似乎最常被提及,但GMT和UTC却被不同的人提及。

出于(几乎)所有实际计算目的,UTC实际上是GMT。 除非您看到带有小数秒的时间戳,否则您将使用GMT进行处理,从而使这种区别变得多余。

存储时间戳时,请按原样包含本地时间偏移(包括DST偏移)。

时间戳始终以GMT表示,因此没有偏移量。


#29楼

在处理数据库(特别是MySQL ,但这适用于大多数数据库)时,我发现很难存储UTC。

  • 默认情况下,数据库通常使用服务器日期时间(即CURRENT_TIMESTAMP)。
  • 您可能无法更改服务器时区。
  • 即使您能够更改时区,您也可能会有第三方代码期望服务器时区为本地。

我发现仅将服务器日期时间存储在数据库中,然后让数据库在SQL语句中将存储的日期时间转换回UTC(即UNIX_TIMESTAMP())会更容易。 之后,您可以在代码中将datetime用作UTC。

如果您可以100%控制服务器和所有代码,则最好将服务器时区更改为UTC。


#30楼

您是否正在使用.NET框架 ? 如果是这样,让我介绍一下.NET 3.5中添加的DateTimeOffset类型。

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

  • DateTimeOffset.Now静态方法将返回一个DateTimeOffset实例,该实例包括当前(本地)时间和本地偏移量(在操作系统的区域信息中定义)。

  • DateTimeOffset.UtcNow静态方法将返回一个DateTimeOffset实例,该实例由UTC中的当前时间组成(就像您在格林威治中一样)。

其他有用的类型是TimeZoneTimeZoneInfo类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值