Как перевести между часовыми поясами Windows и IANA?

Как описано в теге wiki часового пояса, существуют два разных стиля часовых поясов.

  • Те, которые предоставляются Microsoft для использования с Windows и классом .Net TimeZoneInfo, идентифицируются значением, например Eastern Standard Time.

  • Те, которые предоставлены IANA в TZDB, идентифицируются значением, таким как America/New_York.

Многие интернет-интерфейсы API используют часовые пояса IANA, но по многочисленным причинам, возможно, потребуется преобразовать их в идентификатор часового пояса Windows или наоборот.

Как это можно сделать в .Net?

Ответ 1

Основным источником данных для преобразования между идентификаторами часовых поясов Windows и IANA является файл windowsZones.xml, распространяемый в рамках проекта Unicode CLDR.

Тем не менее, CLDR выпускается только дважды в год. Это, наряду с периодической синхронизацией обновлений Windows и нерегулярными обновлениями базы данных часовых поясов IANA, усложняет прямое использование данных CLDR. Имейте в виду, что сами изменения часового пояса производятся по прихоти различных правительств мира, и не все изменения производятся с достаточным уведомлением, чтобы сделать это в этих циклах выпуска до их соответствующих дат вступления в силу.

Есть несколько других крайних случаев, которые необходимо обработать, которые не охватываются строго CLDR, и время от времени появляются новые. Поэтому я инкапсулировал сложность решения в микробиблиотеке TimeZoneConverter, которую можно установить из Nuget.

Использовать эту библиотеку просто. Вот несколько примеров конвертации:

string tz = TZConvert.IanaToWindows("America/New_York");
// Result:  "Eastern Standard Time"

string tz = TZConvert.WindowsToIana("Eastern Standard Time");
// result:  "America/New_York"

string tz = TZConvert.WindowsToIana("Eastern Standard Time", "CA");
// result:  "America/Toronto"

На сайте проекта есть еще примеры.

Важно понимать, что хотя часовой пояс IANA можно сопоставить с одним часовым поясом Windows, обратное неверно. Один часовой пояс Windows может быть сопоставлен с несколькими часовыми поясами IANA. Это можно увидеть в приведенных выше примерах, где Eastern Standard Time отображается как на America/New_York, так и на America/Toronto. TimeZoneConverter доставит тот, который CLDR помечает как "001", известный как "золотая зона", если вы не укажете код страны и не совпадете с другой зоной в этой стране.

Примечание. Этот ответ развивался годами, поэтому комментарии ниже могут относиться или не относиться к текущей редакции. Посмотрите историю изменений для деталей. Благодарю.

Ответ 2

Я знаю, что это старый вопрос, но у меня был вариант использования, которым я хотел бы поделиться здесь, так как это наиболее релевантный пост, который я нашел при поиске. Я разрабатывал приложение .NET Core, используя Docker Linux-контейнер, но для развертывания на сервере Windows. Таким образом, мне нужен был только контейнер Docker Linux для поддержки имен часовых поясов Windows. Это работает без изменения кода приложения, выполнив следующие действия:

cp /usr/share/zoneinfo/America/Chicago "/usr/share/zoneinfo/Central Standard Time"
cp /usr/share/zoneinfo/America/New_York "/usr/share/zoneinfo/Eastern Standard Time"
cp /usr/share/zoneinfo/America/Denver "/usr/share/zoneinfo/Mountain Standard Time"
cp /usr/share/zoneinfo/America/Los_Angeles "/usr/share/zoneinfo/Pacific Standard Time"

Затем в моем .NET-коде следующее работало без каких-либо изменений: TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")