夏令时更改为绝对日期
Posted
技术标签:
【中文标题】夏令时更改为绝对日期【英文标题】:Daylight Saving Time change with an absolute date 【发布时间】:2014-06-27 19:54:36 【问题描述】:我正在尝试在我的闹钟应用中实施正确的 DST 调整处理。因此,我正在阅读 DYNAMIC_TIME_ZONE_INFORMATION 的描述,用于通过 GetTimeZoneInformationForYear API 检索当前的 DST 调整信息,其中包含以下内容:
DaylightDate:
包含日期和本地的SYSTEMTIME 结构 从标准时间过渡到夏令时的时间 在此操作系统上发生。如果时区不支持 夏令时或调用者需要禁用夏令时 时间,SYSTEMTIME 结构中的 wMonth 成员必须为零。如果 此日期已指定,此结构中的 StandardDate 成员必须 也被指定。否则,系统假定时区数据为 无效,不会应用任何更改。选择正确的日期 月份,将 wYear 成员设置为零,wHour 和 wMinute 成员 到过渡时间,wDayOfWeek 成员到适当的 weekday,以及 wDay 成员来指示发生的那一天 一个月内的第几周(1 到 5,其中 5 表示最后一个 如果一周中的那一天没有发生,则在一个月内发生 5 次)。
如果 wYear 成员不为零,则过渡日期为 绝对;它只会发生一次。否则就是亲戚 每年发生的日期。
我还在检查世界各地观察到的current DST adjustments,如果相对 DST 调整看起来很简单,我不太清楚如何通过DYNAMIC_TIME_ZONE_INFORMATION 传达以下调整——只需一个绝对的一个月和一天。
例如:
Egypt
-----
DST Start: May 15
DST End: Last Friday September
或者这个:
Iran
----
DST Start: March 21–22
DST End: September 21–22
有人知道怎么做吗?
【问题讨论】:
埃及是值得注意的,他们将在今年的斋月期间暂停 DST。有人上班要迟到了。 为什么要投票结束?介意先解释一下吗? 你没有问一个很明确的问题。您说过“我正在尝试实施正确的 DST 调整处理......”和“有人知道该怎么做吗?” - 但其余的并没有添加任何内容来澄清您想知道的内容。请编辑您的问题以进一步扩展问题本身。谢谢。 @MattJohnson:对不起,除了我在上面发布的内容之外,我不知道如何描述这个问题。这开始听起来像是一个语言论坛,其中包含如何提出我的问题的所有规则...... 我不想强加任何规则。我正在阅读您的整个问题,但我根本不知道您在问什么。如果我能理解您想知道的内容,我将很乐意提供帮助。我对这个话题很流利,但我不能把我的整个大脑都扔在一个答案上。您能否指导我了解您想了解的具体内容? 【参考方案1】:要了解时区结构,查看以下键下的 Windows 注册表会有所帮助:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
在这里您可以找到the Microsoft time zone database 的所有内置时区,即maintained by Microsoft via Windows Updates。
让我们看一下您提到的一个示例案例:
.\Egypt Standard Time\
.\Egypt Standard Time\Dynamic DST\
从中我们可以看到,2005-2011 年定义了特定的 DST 规则。在这个范围之外,我们回退到根条目的TZI
值。
您会注意到这里缺少 2014 年埃及的条目。那是因为埃及几乎没有通知the upcoming change。您可以期待 Microsoft 的修补程序很快就会随更新一起提供。
将注册表中的二进制数据反序列化为REG_TZI_FORMAT
结构,如下所示:
typedef struct _REG_TZI_FORMAT
LONG Bias;
LONG StandardBias;
LONG DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
REG_TZI_FORMAT;
您应该注意的一个问题是,Windows 不喜欢在午夜转换的时区。解决方法是不要说“九月最后一个星期五的 00:00”,而必须说“九月最后一个星期四的 23:59:59.999”。但是,在这里您必须小心,因为此类规则有时会导致错误的派生日期。为了解决这个问题,有时每年都会有自己的规则。仍然使用重复模式格式而不是固定日期格式,主要是为了保持一致性。
但是,还有另一个问题 - 这种结构一年只能支持两次夏令时转换。一个在 DST 开始时在 DaylightDate
,一个在 DST 结束时在 StandardDate
。由于埃及正在制定夏令时斋月除外,所以会有four transitions。这也发生在Egypt in 2010 中,并且也经常发生在Morocco 中。为应对这一设计缺陷,Microsoft 传统上会发布多个更新,与更改同步。 (例如,请参阅KB2297272。)
我假设 Microsoft 将推出多次更新更改,因此为了举例,我们将省略斋月期间。此规则从 5 月的第 2 个星期三 23:59:59.999 开始夏令时,并在 9 月的最后一个星期四 23:59:59.999 结束。
"TZI" = 88ffffff 00000000 c4ffffff 000009000400050017003b003b00e703 000005000300020017003b003b00e703
这对应于具有这些值的 REG_TZI_FORMAT
结构(为清楚起见,作为 JSON):
"Bias" : -120, // Standard offset is UTC+2
"StandardBias" : 0,
"DaylightBias" : -60, // Subtract an hour for DST
"StandardDate" :
"wYear" : 0, // Recurrence pattern
"wMonth" : 9, // September
"wDayOfWeek" : 4, // Thursday
"wDay" : 5, // Last occurrence
"wHour" : 23,
"wMinute" : 59,
"wSecond" : 59,
"wMilliseconds" : 999
,
"DaylightDate" :
"wYear" : 0, // Recurrence pattern
"wMonth" : 5, // May
"wDayOfWeek" : 3, // Wednesday
"wDay" : 2, // Second occurrence
"wHour" : 23,
"wMinute" : 59,
"wSecond" : 59,
"wMilliseconds" : 999
我认为这个答案已经够长了,所以如果你愿意,我会留给你来推断伊朗的规则。不过,我要指出的是,伊朗的 Windows 数据自 2009 年以来一直不正确,并且尚未收到更新。 :-/
附带说明,如果您想指定一个固定日期规则,您可以提供一个非零的“实际”年份值。然后 day 字段代表实际的一天 - 而不是发生的时间。但是,这通常会被避免,因为它只对适用于个别年份的动态 DST 规则有意义。在根节点的通用 TZI
条目中使用固定日期是没有意义的。
更新
Microsoft 已在 KB2967990 中发布了 2014 年埃及的更新。
【讨论】:
感谢您的解释。请问——你是怎么知道这一切的?我主要担心的是他们引入了一个固定的日期,即 5 月 15 日,这应该是每年都会发生的,我不清楚如何使用 Microsoft 提供的 DST 结构来指定它。但是现在你提出了一个更大的问题——每年超过 2 次 DST 更改。伙计,夏令时搞砸了:) 我刚刚注意到,你来自贝尔维尤。我的邻居。今天我们在西北度过了美好的一天,哈哈。感谢您的帮助! 大部分都在文档中,如果你知道在哪里看的话。可以理解的是,这并不容易!经验也有帮助。是的——今天天气很好,阳光明媚。 :) 如果埃及是您最关心的问题,我会坚持下去。应该很快就会有来自 MS 的官方修补程序。 谢谢。不,我主要关心的是让我的调度程序“不会中断”我没想到的 DST 更改。【参考方案2】:伊朗是一个奇怪的国家,因为 DST 过渡日期不符合 Microsoft 注册表所期望的正常规则。例如:三月的第二个星期日。所以我同意您需要使用绝对日期,但使用注册表格式来实现。 DST 过渡日期的工作日几乎每年都不同。
伊朗夏令时过渡日期基于波斯历 https://mm.icann.org/pipermail/tz/2003-March/012053.html
因此,动态注册方法将是每年都有很多变化的答案!
【讨论】:
以上是关于夏令时更改为绝对日期的主要内容,如果未能解决你的问题,请参考以下文章