夏令时更改为绝对日期

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 成员设置为零,wHourwMinute 成员 到过渡时间,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

因此,动态注册方法将是每年都有很多变化的答案!

【讨论】:

以上是关于夏令时更改为绝对日期的主要内容,如果未能解决你的问题,请参考以下文章

夏令时和 Cron

python time.time() 和“夏令时”

仅从日期计算夏令时

将 UTC 时间戳插入 MySQL - 夏令时时区

亚马逊夏令时可靠性

没有夏令时的日期计算