Я пытаюсь реализовать правильную обработку корректировки DST в моем приложении будильника. Итак, я читаю описание для DYNAMIC_TIME_ZONE_INFORMATION который я использую, чтобы получить информацию о текущей настройке DST через GetTimeZoneInformationForYear API, и это говорит следующее:
DaylightDate:
СИСТЕМНОЕ ВРЕМЯ структура, которая содержит дату и местный
время перехода с стандартного на летнее время
происходит в этой операционной системе. Если часовой пояс не поддерживает
летнее время или если вызывающему абоненту необходимо отключить летнее время
время wMonth член в структуре SYSTEMTIME должен быть нулевым. Если
эта дата указана, член StandardDate в этой структуре должен
Также будет указано. В противном случае система предполагает, что данные часового пояса
недействителен и никакие изменения не будут применены. Чтобы выбрать правильный день в
месяц, установите wYear член к нулю, wHour а также wMinute члены
время перехода, wDayOfWeek член соответствующего
будний день, а WDAY член, чтобы указать на возникновение дня
неделя в течение месяца (от 1 до 5, где 5 означает окончательный
появление в течение месяца, если этот день недели не произошел 5
раз).Если wYear член не ноль, дата перехода
абсолютный; это произойдет только один раз. В противном случае это относительный
дата, которая происходит ежегодно.
Я также проверяю текущие корректировки DST наблюдаются во всем мире, и если относительные корректировки 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
Кто-нибудь знает как это сделать?
Чтобы понять структуру часового пояса, полезно взглянуть на реестр Windows под следующим ключом:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
Здесь вы найдете все встроенные часовые пояса база данных часовых поясов Microsoft, который поддерживается Microsoft через Windows Updates.
Давайте рассмотрим один из приведенных вами примеров:
.\Egypt Standard Time\
.\Egypt Standard Time\Dynamic DST\
Отсюда видно, что существуют определенные правила перехода на летнее время, определенные на 2005-2011 годы. За пределами этого диапазона мы возвращаемся к TZI
значение корневой записи.
Вы заметите, что там отсутствует запись 2014 года для Египта. Это потому, что Египет почти не уведомил о предстоящее изменение. Вы можете ожидать, что скоро будет доступно исправление от 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 в последнюю Четверг в сентябре «. Однако, здесь вы должны быть осторожны, потому что подобные правила могут иногда приводить к ошибочным производным датам. Чтобы противостоять этому, иногда каждый год будет иметь свое собственное правило. Формат шаблона повторения все еще используется, а не фиксированный формат даты, в основном для согласованности.
Однако есть еще одна проблема — эта структура может поддерживать только два перехода на летнее время в год. Один на DaylightDate
когда начинается летнее время, и один на StandardDate
когда заканчивается летнее время. С тех пор как Египет принимает DST кроме Рамадана, будут четыре перехода. Это также произошло в Египет в 2010 году, а также регулярно происходит в Марокко. Чтобы справиться с этим недостатком дизайна, Microsoft традиционно выпустила множественный обновления, приуроченные к изменениям. (Например, см. KB2297272.)
Я предполагаю, что Microsoft вытолкнет изменения с многократным обновлением, поэтому в качестве примера мы пропустим период Рамадана. Это правило начинается в летнее время во 2-ю среду мая в 23: 59: 59,999 и заканчивается в последний четверг сентября в 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 года и до сих пор не получили обновления. : — /
В качестве примечания: если вы хотите указать правило с фиксированной датой, вы можете указать ненулевое значение «реального» года. Тогда поле дня представляет фактический день, а не происшествие. Однако этого обычно избегают, поскольку это имеет смысл только для правил динамического перехода на летнее время, которые применяются к отдельным годам. Не имеет смысла использовать фиксированную дату в общем TZI
запись в корневом узле.
ОБНОВИТЬ
Microsoft выпустила обновление для Египта на 2014 год в KB2967990.
Иран странен тем, что даты перехода на летнее время не соответствуют нормальным правилам, которые ожидает реестр Microsoft. Например: 2-е воскресенье марта. Поэтому я согласен, что вам нужно использовать абсолютные даты, но это достигается с помощью формата реестра. Дни перехода на летнее время меняются почти каждый год.
Даты перехода на летнее время в Иране основаны на персидском календаре
https://mm.icann.org/pipermail/tz/2003-March/012053.html
Таким образом, метод динамического реестра будет ответом с большим количеством изменений каждый год!