夏令时随绝对日期而变化

时间:2014-05-09 23:21:08

标签: c++ windows winapi dst

我正在尝试在闹钟应用中实施正确的DST调整处理。所以我正在阅读DYNAMIC_TIME_ZONE_INFORMATION的说明,用于通过GetTimeZoneInformationForYear API检索当前的DST调整信息,并说明如下:

  

DaylightDate

     

包含日期和本地的SYSTEMTIME结构   从标准时间过渡到夏令时的时间   发生在此操作系统上。如果时区不支持   夏令时或者呼叫者需要禁用夏令时   时间,SYSTEMTIME结构中的 wMonth 成员必须为零。如果   指定此日期,此结构中的StandardDate成员必须   也可以指定。否则,系统假定时区数据为   无效,不会应用任何更改。选择正确的日期   月份,将 wYear 成员设置为零, wHour wMinute 成员   到了过渡时间, wDayOfWeek 成员要适当   工作日和 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

有谁知道怎么做?

2 个答案:

答案 0 :(得分:3)

要了解时区结构,有助于在以下密钥下查看Windows注册表:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

在这里,您可以找到the Microsoft time zone database的所有内置时区,即maintained by Microsoft via Windows Updates

让我们看看你提到的一个例子:

.\Egypt Standard Time\

Egypt

.\Egypt Standard Time\Dynamic DST\

Egypt 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并不喜欢在午夜过渡的时区。解决方法是在9月的最后一个星期五和#34;而不是说" 00:00,而不是在9月的最后星期四" 23:59:59.999& #34 ;.但是,在这里你必须要小心,因为像这样的规则有时会导致错误的派生日期。为了解决这个问题,有时每年都会有自己的规则。仍然使用重复模式格式而不是固定日期格式,主要是出于一致性目的。

但是,还有另一个问题 - 这种结构只能支持一年内两个夏令时的转换。 DST开始时DaylightDate,DST结束时StandardDate一个。由于埃及正在制定DST ,除了斋月,因此会有four transitions。这也发生在Egypt in 2010中,并且也定期发生在Morocco中。为了解决这个设计缺陷,微软传统上发布了多个更新,时间恰好与变化相吻合。 (例如,请参阅KB2297272。)

我假设微软会推出多次更新,所以为了举个例子,我们将省略斋月期。该规则于5月的第2个星期三23:59:59.999开始DST,并于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
    }
}

我认为这个答案足够长,所以如果你愿意,我会留给你推断伊朗的规则。尽管如此,我还是指出,自2009年以来,伊朗的Windows数据一直不正确,尚未收到更新。 : - /

作为旁注,如果要指定固定日期规则,则可以提供非零"真实"年价值。然后,day字段表示实际的日期 - 而不是发生的日期。但是,通常会避免这种情况,因为它仅对适用于各个年份的动态DST规则有意义。在根节点中的通用TZI条目中使用固定日期是没有意义的。

<强>更新

Microsoft已在KB2967990发布了2014年埃及的更新。

答案 1 :(得分:0)

伊朗是一个奇怪的问题,因为DST过渡日期不符合Microsoft注册管理机构预期的正常规则。例如:三月的第二个星期天。所以我同意您需要使用绝对日期,但使用注册表格式。 DST过渡日期的工作日几乎每年都有所不同。

伊朗DST过渡日期基于波斯日历 https://mm.icann.org/pipermail/tz/2003-March/012053.html

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