Определите, применяется ли переход на летнее время к определенной дате - PullRequest
3 голосов
/ 12 января 2020

Я пытаюсь изменить даты создания файлов на дату их выпуска. Сначала я конвертирую строку типа «2 апреля 2005» в std::tm. Затем я создаю SYSTEMTIME следующим образом:

std::tm dt = from_string("2 April 2005");
SYSTEMTIME st { 0 };
st.wYear = dt.tm_year + 1900; // dt is years from 1900
st.wMonth = dt.tm_mon + 1; // dt is month index 0
st.wDay = dt.tm_mday;
st.wHour = 6; // FILETIME is based on UTC, which is 6 hours ahead

Затем я преобразую SYSTEMTIME в FILETIME и использую его для применения изменений.

Это устанавливает время файла до 2 April 2005 12:00:00 AM, что правильно. Однако для видео после 2 апреля было установлено значение 1:00:00 AM, и, конечно же, переход на летнее время произошел 3 апреля 2005 года.

Как определить, является ли определенная дата до или после перехода на летнее время, чтобы я мог настроить st.wHour соответственно? Цель состоит в том, чтобы все время было установлено на 12:00:00 AM. Желательно, чтобы это работало как с датами 60-х, так и с текущими.

Я пытался использовать TIME_ZONE_INFORMATION и GetTimeZoneInformation, но возвращаюсь только TIME_ZONE_ID_STANDARD.

1 Ответ

2 голосов
/ 14 января 2020

Несколько вещей:

  • SYSTEMTIME - это простая структура. Он имеет отдельные поля для года, месяца, дня недели, дня (месяца), часа, минуты, секунды и миллисекунды. Это не UT C или местное время, или что-то еще само по себе. Это не учитывается, пока вы не передадите его в функцию.

  • FILETIME - это еще одна простая структура. Он представляет количество интервалов в 100 наносекунд с полуночи 1601-01-01. Большая часть документации заставит вас думать, что это всегда в UT C, но есть функции, подобные FileTimeToLocalFileTime, которые опровергают это. Таким образом, подобно SYSTEMTIME, каждая отдельная функция должна решать, как ее интерпретировать.

  • Функция SystemTimeToFileTime принимает указатель на SYSTEMTIME, который интерпретируется как UT C и возвращает указатель на FILETIME, что также в терминах UT C. Не задействован местный часовой пояс.

  • Не пытайтесь самостоятельно настраивать местное время (st.wHour = 6 в вашем коде). Час будет меняться в зависимости от часового пояса и летнего времени.

  • Вы не видели никакого ответа от GetTimeZoneInformation, кроме TIME_ZONE_STANDARD, потому что это говорит вам о том, что в настоящее время действует - что не связано с датами, с которыми вы, возможно, работаете.

  • Вы не должны пытаться выяснить, как настроить DST самостоятельно. ТЛЧ не универсально применим, и это не всегда один час смещения. Вместо этого используйте функцию, которая преобразует из часового пояса, который вас интересует, в UT C.

В конечном счете, звучит так, будто вы спрашиваете, как установить время файла в полночь местный часовой пояс на определенную дату. Таким образом, я предлагаю вам go, выполнив следующие действия:

  • Создайте SYSTEMTIME с датой, которая вас интересует, и компонентами времени, установленными в нули (по умолчанию).

  • Получить местный часовой пояс с помощью функции GetDynamicTimeZoneInformation. Требуется версия «dynamici c», которая учитывает любые исторические различия в правилах для стандартного времени и летнего времени, о которых знает Windows, а не только текущий набор правил.

  • Передайте эти два значения в функцию TzSpecificLocalTimeToSystemTimeEx. Он будет интерпретировать входное время как находящееся во входном часовом поясе (который был локальным часовым поясом системы). В результате получается FILETIME в единицах UT C.

  • . Передайте это значение в SetFileTime, что предполагает ввод в единицах UT C.

Кроме того, имейте в виду, что не все файловые системы отслеживают время файла одинаково :

  • NTFS сохраняет фактическое время UT C, поэтому вы можете перемещать файлы между компьютерами, и временная метка представляет одну и ту же точку в универсальном времени, даже если компьютеры имеют разные настройки часового пояса.

  • FAT и его варианты хранить местное время. Поэтому, когда вы звоните SetFileTime, Windows переводится из UT C в местный часовой пояс и записывает результат. Если вы затем откроете файл в системе с другим часовым поясом, дата будет интерпретирована как , что , что приведет к другому времени UT C. (Это часто наблюдается на USB-накопителях, картах памяти и т. Д. c. При перемещении файлов с камер на компьютеры.)

Наконец, вы сказали:

... Желательно, чтобы это работало как с датами 60-х годов, так и с текущими.

К сожалению, Windows часовые пояса не отслеживают исторические даты так далеко. Политика Microsoft в отношении часовых поясов предназначена для отслеживания часовых поясов и правил перехода на летнее время на 2010 год и далее для всех населенных пунктов на Земле. Хотя в нескольких часовых поясах отслеживаются некоторые исторических изменений, произошедших до 2010 года, как артефактов до того, как эта политика была формализована. (Они точны в пределах данной зоны, но не одинаковы в начальные годы во всех зонах).

Если исторические даты важны для вашего приложения, вам понадобится совсем другой подход - тот, который не использует данные часового пояса Windows, а вместо этого использует базу данных часовых поясов IANA . (Подробнее об этом в теге часового пояса wiki .) Вот несколько идей, которые вы можете изучить:

  • Проект ICU имеет поддержку часовых поясов и C реализация . Это немного тяжело для этой цели, но хорошо, если вы используете его для других аспектов локализации приложения.

  • У Говарда Хиннанта (который прокомментировал вопрос выше) есть превосходный Библиотека дат с поддержкой часового пояса IANA.

  • Может быть возможно получить то, что вам нужно, из класса Windows.Globalization.Calendar UWP. Я не проверял, будет ли он использовать исторические правила из данных IANA или данные Windows. (Если у меня будет возможность проверить, я вернусь и обновлю этот ответ.)

Имейте в виду, что база данных IANA гарантирует только с 1970 года. Вы сказали, что вам это нужно с 1960 года, и хотя есть некоторые зоны с данными для этого (а некоторые намного старше), нет никаких гарантий правильности в этот период.

...