夏令时和时区最佳实践[关闭] DateTimeZone :: listAbbreviations()

问题描述 投票:1968回答:30

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

如果您有任何要添加的内容,请执行此操作

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

例如,在订单获取系统中有一个业务规则取决于订单的时间 - 如果时钟发生变化,规则可能不那么明确。如何保持订单的时间?当然有无数的场景 - 这只是一个说明性的场景。

  • 你是如何处理夏令时问题的?
  • 您的解决方案中有哪些假设? (在这里寻找背景)

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

  • 你尝试了哪些不起作用?
  • 为什么不起作用?

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

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

datetime timezone utc dst datetimeoffset
30个回答
872
投票

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

做:

  • 无论何时提到确切的时刻,都要按照不受夏令时影响的统一标准来保持时间。 (GMT和UTC在这方面是相同的,但最好使用术语UTC。请注意,UTC也称为Zulu或Z时间。)
  • 相反,如果您选择使用本地时间值保留时间,请包括UTC时此特定时间的本地时间偏移量(此偏移量可能会在一年中发生变化),以便稍后可以明确地解释时间戳。
  • 在某些情况下,您可能需要存储UTC时间和等效的本地时间。通常这是通过两个单独的字段完成的,但是一些平台支持datetimeoffset类型,它可以存储在单个字段中。
  • 将时间戳存储为数值时,请使用Unix time - 这是自1970-01-01T00:00:00Z以来的整秒数(不包括闰秒)。如果需要更高的精度,请使用毫秒。此值应始终基于UTC,不进行任何时区调整。
  • 如果以后可能需要修改时间戳,请包含原始时区ID,以便确定偏移量是否与记录的原始值相比有所变化。
  • 在调度未来事件时,通常优先选择本地时间而不是UTC,因为更改偏移是常见的。 See answerblog post
  • 存储整个日期(例如生日和纪念日)时,请勿转换为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,现在在maintenance-mode。 Joda-Time,ThreeTen-Backport,ThreeTen-Extra,java.time类和JSR 310由同一个人Stephen Colebourne领导。
  • 如果使用.NET,请考虑使用Noda Time
  • 如果使用没有Noda Time的.NET,请考虑DateTimeOffset通常是比DateTime更好的选择。
  • 如果使用Perl,请使用DateTime
  • 如果使用Python,请使用pytzdateutil
  • 如果使用JavaScript,请使用带有moment.js扩展名的moment-timezone
  • 如果使用PHP> 5.2,请使用DateTimeDateTimeZone类提供的本机时区转换。使用DateTimeZone::listAbbreviations()时要小心 - see answer。为了使PHP保持最新的Olson数据,请定期安装the timezonedb PECL包; see answer
  • 如果使用C ++,请务必使用正确实现IANA timezone database的库。这些包括cctzICUHoward Hinnant's "tz" library。 不要使用Boost进行时区转换。虽然its API声称支持标准的IANA(又名“zoneinfo”)标识符,但它将crudely maps them转换为POSIX样式的数据,而不考虑每个区域可能具有的丰富变化历史。 (此外,该文件已不再用于维护。)
  • 如果使用Rust,请使用chrono
  • 大多数业务规则使用民用时间,而不是UTC或GMT。因此,计划在应用应用程序逻辑之前将UTC时间戳转换为本地时区。
  • 请记住,时区和偏移不是固定的,可能会改变。例如,历史上美国和英国使用相同的日期来“前进”和“后退”。然而,在2007年,美国改变了时钟变换的日期。这意味着一年中的48周,伦敦时间和纽约时间之间的差异是5小时和4周(春季3个,秋季1个),这是4个小时。在涉及多个区域的任何计算中都要注意这样的项目。
  • 考虑时间类型(实际事件时间,广播时间,相对时间,历史时间,重复时间)您需要存储哪些元素(时间戳,时区偏移和时区名称)以便正确检索 - 请参阅“时间类型” this answer
  • 保持您的操作系统,数据库和应用程序tzdata文件在它们与世界其他地方之间保持同步。
  • 在服务器上,将硬件时钟和OS时钟设置为UTC而不是本地时区。
  • 无论前一个要点如何,服务器端代码(包括网站)都不应该期望服务器的本地时区特别适合。 see answer
  • 首选在应用程序代码中逐个使用时区,而不是通过配置文件设置或默认值全局使用。
  • 在所有服务器上使用NTP服务。
  • 如果使用FAT32,请记住时间戳存储在本地时间,而不是UTC。
  • 在处理周期性事件(例如每周电视节目)时,请记住时间随着夏令时的变化而变化,并且在不同时区会有所不同。
  • 始终将日期时间值查询为lower-bound inclusive, upper-bound exclusive>=<)。

别:

  • 不要混淆“时区”,如America/New_York和“时区偏移”,如-05:00。他们是两个不同的东西。见the timezone tag wiki
  • 不要使用JavaScript的Date对象在较旧的Web浏览器中执行日期和时间计算,因为ECMAScript 5.1及更低版本的a design flaw可能会错误地使用夏令时。 (这已在ECMAScript 6/2015中修复)。
  • 永远不要相信客户的时钟。这可能是不正确的。
  • 不要告诉人们“始终使用UTC”。这种广泛的建议是本文前面所述的几种有效方案的短视。而是对您正在使用的数据使用适当的时间参考。 (时间戳可以使用UTC,但未来的时间安排和仅限日期的值不应该使用。)

测试:

  • 在测试时,请确保您测试西部,东部,北部和Southern半球的国家(实际上在全球每个地区,所以4个地区),DST正在进行中而不是(给出8个),以及一个国家不使用DST(另外4个覆盖所有区域,共计12个)。
  • 测试DST的过渡,即当您在夏季时,从冬季选择时间值。
  • 使用DST测试边界情况,例如UTC + 12的时区,使当地时间为UTC+13 in summer and even places that are UTC+13 in winter
  • 测试所有第三方库和应用程序,并确保它们正确处理时区数据。
  • 至少测试半小时的时区。

参考:

其他:

  • 大厅让你的代表结束美国夏令时的憎恶。我们总能希望......
  • Earth Standard Time的大堂

16
投票

虽然我没有尝试过,但我觉得引人注目的时区调整方法如下:

  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或类似方法来执行查询而不是访问数据库。

这些数据可以从public domain tz database中提取出来。

这种方法的优点和脚注:

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

现在,这种方法或任何其他方法的唯一缺点是从本地时间到GMT的转换并不完美,因为任何对时钟具有负偏移的DST改变都会重复给定的本地时间。我担心,没有简单的方法可以解决这个问题,这也是存储当地时间的一个原因。


14
投票

我已经在两种类型的系统上实现了这一点,“轮班规划系统(例如工厂工人)”和“气体依赖管理系统”......

23和25小时的长日是一个痛苦应对,因此8小时轮班需要7小时或9小时。问题是你会发现每个客户,甚至客户的部门都有不同的规则(通常没有记录)他们在这些特殊情况下做了什么。

在他们为您的“现成”软件付款之前,最好不要询问客户的一些问题。在购买软件时,很难找到预先考虑此类问题的客户。

我认为在所有情况下,您都应该记录UTC时间并在存储日期/时间之前转换为/从本地时间转换。但是,即使知道哪些时间占用了一段时间,也可能很难使用夏令时和时区。


13
投票

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

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

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

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


12
投票

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

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

服务器端代码(包括网站)绝不应该期望服务器的本地时区特别是任何东西。

在某些语言中,本地时区可以很容易地进入应用程序代码。例如,.NET中的DateTime.ToUniversalTime方法将从本地时区转换为UTC,DateTime.Now属性返回本地时区的当前时间。此外,JavaScript中的Date构造函数使用计算机的本地时区。还有很多这样的例子。执行防御性编程非常重要,避免使用计算机本地时区设置的任何代码。

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


11
投票

对于网络来说,规则并不复杂......

  • 服务器端,使用UTC
  • 客户端,使用Olson 原因:UTC偏移不是夏令时安全(例如纽约是EST(UTC - 5小时)部分时间,EDT(UTC - 4小时)其余时间)。 对于客户端时区确定,您有两种选择: 1)有用户设置区域(更安全) 资源:Web-ready Olson tz HTML DropdownJSON 2)自动检测区域 资源:jsTimezoneDetect

其余的只是使用服务器端日期时间库的UTC /本地转换。很高兴...


10
投票

将服务器设置为UTC,并确保它们都配置为ntp或等效服务器。

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


9
投票

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


7
投票

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

去年我们遇到过一种情况,即使我们使用基于UTC的系统,我们的时间在北美用户的三周时间内一直持续一小时。

事实证明它最终是服务器。他们只需要应用最新的补丁(Windows Server 2003)。


6
投票

PHP's DateTimeZone::listAbbreviations() output

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

5
投票

如果您碰巧维护使用DST活动的数据库系统,请仔细检查是否需要在秋季过渡期间关闭它们。 Mandy DBS(或其他系统)也不喜欢在(本地)时间两次传递相同的点,这正是你在秋季转回时钟时发生的事情。 SAP已经通过(恕我直言)非常简洁的解决方案解决了这个问题 - 他们只是让内部时钟以正常速度的一半运行两个小时......


305
投票

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

时代的类型

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

  1. 活动时间:例如,国际体育赛事发生的时间,或加冕/死亡/等等。这取决于事件的时区而不是观众的时区。
  2. 电视时间:例如,特定的电视节目在当地时间晚上9点播出。在考虑在您的网站上发布结果(比如说“美国偶像”)时很重要
  3. 相对时间:例如:这个问题在21小时内有一个开放的赏金。这很容易显示
  4. 重复时间:例如:即使DST发生变化,每周一晚上9点都有电视节目。

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

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

存放时间

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

Offsets and names

以上的一个例子是:

足球世界杯决赛比赛于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-05-01到1937-06-30,荷兰的标准时间恰好是UTC的19分和32.13秒。使用HH:MM格式无法准确表示此时区。

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


5
投票

业务规则应始终适用于civil time(除非有立法另有说明)。请注意,民用时间是一团糟,但它是人们使用的,所以它是重要的。

在内部,将时间戳保持在像纪元的民间时间之类的东西中。 epoch并不重要(我赞成Unix epoch)但它确实使事情变得更容易。假设leap-seconds不存在,除非你正在做一些真正需要它们的东西(例如,卫星跟踪)。时间戳和显示时间之间的映射是应该应用DST规则的唯一点;规则经常变化(在全球范围内,一年几次;责怪政治家)所以你应该确保你不对映射进行硬编码。奥尔森的TZ database非常宝贵。


4
投票

您使用的是.NET框架吗?如果是这样,让我向您介绍使用.NET 3.5添加的DateTimeOffset类型。

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

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

其他有用的类型是TimeZoneTimeZoneInfo类。


4
投票

对于那些在.NET上挣扎的人来说,看看使用DateTimeOffset和/或TimeZoneInfo是值得的。

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


2
投票

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

始终按照不受夏令时影响的统一标准保持时间。不同的人已经提到了GMT和UTC,尽管UTC似乎最常提到。

对于(几乎)所有实际计算目的,UTC实际上是GMT。除非你看到一个小数秒的时间戳,否则你正在处理GMT,这使得这种区分变得多余。

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

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


2
投票

这是我的经历: -

(不需要任何第三方库)

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

2
投票

Tom Smith在Computerphile频道上的video about timezones on YouTube也有一个很好的,有趣的描述。例子包括:

  • 萨摩亚(太平洋上的一个岛屿)将其时区向前移动了24小时,使澳大利亚和新西兰的交易变得更加容易,
  • 西岸,有2个人口跟随不同的时区,
  • 18世纪从儒略历到公历(发生在20世纪的俄罗斯)。

1
投票

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


1
投票

永远不要只依靠建设者

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

由于DST,当某个日期时间不存在时,它们可以抛出异常。相反,构建自己的方法来创建此类日期。在其中,捕获由于DST而发生的任何异常,并使用转换偏移调整所需的时间。根据时区,夏令时可能发生在不同的日期和不同的时间(甚至是巴西的午夜)。


1
投票

只是一个例子来证明处理时间是描述的巨大混乱,并且你永远不会自满。在这个页面的几个点上,闰秒被忽略了。

几年前,Android操作系统使用GPS卫星获取UTC时间参考,但忽略了GPS卫星不使用闰秒这一事实。直到新年前夜出现混乱时才有人注意到,当时苹果手机用户和Android手机用户的间隔时间相差约15秒。

我认为它已被修复,但你永远不知道这些“小细节”什么时候会回来困扰你。


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

¹struct tm的一些实现确实存储了UTC偏移量,但这并未使其成为标准。


85
投票

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

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

“物理”时刻是物理学处理的连续通用时间线中的一个点(当然忽略相对论)。例如,这个概念可以用UTC充分编码 - 持久化(如果你可以忽略闰秒)。

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

这个问题令人困惑,因为我们可以互换地谈论这些类型的事件,因为民事时代受政治变化的影响。对于未来的事件,问题(以及区分这些概念的必要性)变得更加明显。示例(取自我的讨论here

约翰在他的日历中记录了日期时间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给我打电话”时,知道约翰在概念上的含义。

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

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

一些日期/时间API获得了这种区别:其中包括Jodatime,它是下一个(第三个!)Java DateTime API(JSR 310)的基础。


-4
投票

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

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

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

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


56
投票

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

另外,决定你的实际观众是什么,你不需要服务什么,以及你在哪里画线。不要触摸异国情调的日历,除非您实际上有重要的客户,然后考虑仅针对该区域的单独的面向用户的服务器。

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

如果涉及历史审计义务(比如确切知道2月前Jo在AZ支付账单的时间是9月),那么保留UTC和当地时间进行记录(您的转换表将在一段时间内发生变化)。

为批量生成的数据定义时间参考时区 - 如文件,Web服务等。假设East Coast公司在CA中有数据中心 - 您需要询问并知道他们使用什么作为标准而不是假设其中一个。

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


39
投票

你需要了解Olson tz database,它可以从 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(以及美国/太平洋等同义词)。

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

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


奥尔森的数据有所改变,部分原因是因为A D Olson将很快退休,部分原因是因为版权侵权的维护者有一项(现已被驳回)法律诉讼。现在,时区数据库是在互联网号码分配机构IANA的主持下进行管理的,并且首页上有一个链接到'Time Zone Database'。讨论邮件列表现在是[email protected];公告名单是[email protected]


25
投票

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

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

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


23
投票

越过“计算机时间”和“人们时间”的界限是一场噩梦。主要的一点是,时区和夏令时的规则没有任何标准。各国可随时自由改变其时区和DST规则,而且确实如此。

一些国家,以色列,巴西,每年决定何时进行夏令时,因此无法提前知道(如果)DST何时生效。其他人有关于DST何时生效的固定(ish)规则。其他国家不使用夏令时。

时区不一定与格林威治标准时间完全不同。尼泊尔是+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的国家/地区(总共6个)。


19
投票

对于PHP:

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

但是,PHP没有像Olson DB那样频繁更新,因此仅使用PHP时区转换可能会留下过时的DST信息,并影响数据的正确性。虽然预计这种情况不会频繁发生,但如果全球拥有大量用户,情况可能会发生。

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


16
投票

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

我知道有些人可能听起来很疯狂但是考虑一下用户体验:用户处理的时间比相对日期(今天,昨天,下周一)快于绝对日期(2010.09.17,周一9月17日)。当你考虑更多时,时区(和DST)的准确性越接近now(),所以如果你能用相对格式表示日期/日期时间+/- 1或2周,其余的日期可以是UTC,对95%的用户来说都不会太重要。

这样,您可以以UTC格式存储所有日期,并以UTC格式进行相对比较,只显示相对日期阈值之外的用户UTC日期。

这也可以应用于用户输入(但通常以更有限的方式)。从只有{昨天,今天,明天,下周一,下周四}的下拉菜单中选择对于用户来说比日期选择器更简单,更容易。采摘日期是形式填充最痛苦的组成部分。当然,这对所有情况都不适用,但你可以看到它只需要一点巧妙的设计就可以使它变得非常强大。

© www.soinside.com 2019 - 2024. All rights reserved.