作为一名微软员工,我在Windows时区数据方面有着重要的参与。请放心,微软非常努力地确保发布更新以尽可能准确地维护Windows时区数据。
其中存在一些挑战,包括政府规定的
时区更改时间。例如,我们最近
发布了关于斐济、塞浦路斯、苏丹、汤加、纳米比亚和特克斯和凯科斯群岛即将发生的Windows时区更改的通知。在某些情况下,我们可以满足这些不同政府制定的有效日期。但在某些情况下,我们无法做到这一点,因为政府没有提供足够的提前通知时间。
考虑最近苏丹的情况,他们在
IANA tz邮件列表于2017年10月17日通知了将于2017年11月1日生效的变更。 IANA已经处理了此更改,Microsoft也是如此。但由于短时间内通知,以及在Windows操作系统中处理此类更改需要的时间,将需要一段时间才能创建新的
"苏丹标准时间"
时区在Windows时区数据中。因此,我们发布了临时指导方针,暂时使用其他时区,等到有正确反映受影响地区时间完整历史记录的数据后再切换回来。
关于您提到的Windows时区
"E.南美洲标准时间"
,时区数据是正确的。如果您展开注册表条目,您会发现有一个名为"Dynamic DST"的子键,其中包含逐年更改数据。对于某些时区,这根本不必要,而对于其他时区,您会发现很少的数据,因为同一规则每年都会重复。但是在巴西的情况下,您会注意到动态DST条目为2009年至2040年。
![Windows TZ Registry Data](https://istack.dev59.com/7q2Ke.webp)
(点击图像查看完整分辨率,并注意我手动标记为红色的随年份变化的区域)
动态 DST条目支持Win32 DYNAMIC_TIME_ZONE_INFORMATION
结构和相应的"dynamic"命名的API,例如GetDynamicTimeZoneInformation
。(它们还支持.NET Framework中的System.TimeZoneInfo
类。)这些API中的大多数自Windows Vista / Server 2008以来已经存在,其他一些则在Windows 7 / Server 2012中出现。
请注意,来自当前年份动态规则的TZI
条目被内部Windows进程复制到父键中。这支持使用Win32 TIME_ZONE_INFORMATION
结构的API,这些API自Windows 2000以来一直存在。
回答您提出的具体问题:
我是否正确理解了重复规则?
您引用的特定规则仅适用于2017年,它表示夏令时在第二个月(2月)的第三个星期六以当地时间23:59:59.999结束,然后在第十个月(10月)的第二个星期六以当地时间23:59:59.999开始。请记住,巴西位于南半球,因此夏令时在年末开始,在下一年早期结束。
此外,你可能会想知道为什么周六的时间是23:59:59.999而不是周日的00:00:00.000。这是历史的产物。过去曾有某些程序和进程错误地使用
<=
而不是
<
来评估转换,因此会意外地将时钟向前移动一毫秒进入下一天,然后又回到当前天,再次进入下一天。由错误更改日期引发的事件可能会导致进一步的问题。微软已尽力修复这些错误,但仍然选择偏差1毫秒,而不是冒着有一天在新的地方出现问题的风险。(这仅适用于恰好在午夜发生转换的情况。)
是否存在关于几个时区,特别是“E.南美洲标准时间”的已知问题?
对于该时区没有已知问题,但是已知Windows时区(即使具有动态DST数据)最多只能支持单年内两个时区转换。因此,在像摩洛哥
每年转换四次这样的地方,存在一些内部解决方法,使得“当前”时区数据与本地时间同步,但不能在任何给定时间正确表示整年的所有时间点。
我们目前也没有适用于南极洲特洛尔站的时区映射。原因是从2005年到2015年,这个研究站(人口少于50)每年都要切换三个不同的偏移量(UTC+0、UTC+1和UTC+2)。
如果您的应用程序对上述情况有关键依赖,则建议使用具有IANA数据源的API,而不是Win32 API。
为什么夏令时开始日期明显在每年的第10月的第3周,却被设置在第2周?
是的,如上所述,这是由于1毫秒的有意错误。在巴西部分实行夏令时的地区,2017年夏令时从10月15日星期日00:00:00.000开始。那是本月的第三个星期日。 1毫秒之前是10月14日星期六23:59:59.999,这是本月的第二个星期六。这可能每年都不同,这就是为什么需要动态夏令时数据的原因。
Windows注册表中写入的时区是否可靠?如果不可靠,哪个Windows API函数应该用于将具有DST的时区从写入在与本地机器上设置的时区不同的日期中进行转换?
如果您正在使用Win32 API,则它们会自己使用注册表数据,因此无需直接处理注册表数据。您应该优先选择“动态”版本的API,因为它们可以正确地考虑动态DST数据的年度变化。有时这些被标记为“Ex”。例如,您所询问的函数最好由
TzSpecificLocalTimeToSystemTimeEx
函数处理。
...
如果你的应用程序能够避免使用Windows时区数据,我建议你这样做。最好使用IANA数据源或者派生自它们的数据源。有很多方法来处理IANA时区数据。在WinRT/UWP中,像
Windows.Globalization.Calendar
和
Windows.Globalization.DatetimeFormatting.DateTimeFormatter
这样的新Windows API确实使用
IANA时区,这是未来的发展方向。在标准C++领域,我强烈推荐使用
Howard Hinnant的date/tz库或
ICU项目提供的库。还有其他几个可行的选择。