我希望使这个问题及其答案成为处理夏时制(尤其是处理实际变更)的权威指南。
如果您要添加任何内容,请执行
许多系统都依赖于保持准确的时间,问题在于夏时制导致的时间变化-向前或向后移动时钟。
例如,一个在接订单系统中有取决于订单时间的业务规则-如果时钟改变,则规则可能不太清楚。 订购时间应如何保留? 当然,有无数种情况-这只是一种说明。
- 您如何处理夏令时问题?
- 解决方案中包含哪些假设? (在此处查找上下文)
同样重要,如果不是这样的话:
- 您尝试了什么却不起作用?
- 为什么不起作用?
我会对编程,操作系统,数据持久性以及该问题的其他相关方面感兴趣。
一般的答案很好,但是我也想看看细节,特别是如果它们仅在一个平台上可用。
#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小时))。
- 对于客户端时区确定,您有两个选择:
- 1)有用户设置区域(更安全)
- 资源:支持Web的Olson tz HTML Dropdown和JSON
- 2)自动侦测区
- 资源: jsTimezoneDetect
- 1)有用户设置区域(更安全)
剩下的只是使用服务器端日期时间库的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也称为Zulu或Z 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及更高版本。
- 大部分java.time功能都被反向移植到ThreeTen-Backport库中的Java 6和7中。
- 在ThreeTenABP库中进一步适用于早期的Android(<26)