Як перекласти між часовими поясами Windows та IANA?


149

Як описано у вікі тегів часового поясу , є два різних стилі часових поясів.

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

  • Ті, які IANA надає в TZDB та використовуються TimeZoneInfoкласом .NET при запуску на Linux або OSX, ідентифікуються таким значенням, як "America/New_York".

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

Як це можна досягти в .Net?

Відповіді:


198

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

Однак 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", відомий як "золота зона", якщо ви конкретно не вкажете код країни та не буде відповідати іншій зоні в цій країні.

Примітка. Ця відповідь розвивалася протягом багатьох років, тому коментарі нижче можуть або не стосуються поточної редакції. Перегляньте історію редагування для отримання детальної інформації. Дякую.


1
використання цього методу при перетворенні (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhiдає Asia/Calcuttaце має бути Asia/Kolkata. здається, що TzdbDateTimeZoneSourceмістить старі значення.
Анто Субаш

1
@MattJohnson при перетворенні методу Asia/Kolkataвикористання IanaToWindowsне вдається. але це працює, з Asia/Calcuttaяким старе ім'я. Ви оновили метод, WindowsToIanaале IanaToWindowsтакож є та сама проблема. кілька інших зон , які не працюють в America/Argentina/Buenos_Aires, America/Indiana/Indianapolis, Asia/Kathmandu.
Анто Субаш

1
@AntoJSubash - знову ж чудове спостереження! Я відредагував IanaToWindowsметод компенсації. Дуже дякую!
Метт Джонсон-Пінт

2
@MattJohnson Я другого спостереження @ sirrocco. Використання канонічного ідентичного тесту теж подобалося var canonical = tzdbSource.CanonicalIdMap[ ianaZoneId ]; links = Enumerable.Repeat( canonical, 1 ).Concat( links );мені.
Йоханнес Рудольф

2
@sirrocco - Вибачте, що раніше не побачив ваш коментар. Оновлено функції. Дякую!
Метт Джонсон-Пінт

4

Я знаю, що це старе питання, але у мене був випадок використання, який я хотів би поділитися тут, оскільки це найрелевантніша публікація, яку я знайшов під час пошуку. Я розробляв додаток .NET Core за допомогою контейнера Linux docker, але для розгортання на сервері 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")


1
Це якесь неабияке чудове мислення! Це здається, що це повинно бути нормально, якщо ви охоплюєте кілька конкретних часових поясів. Майте на увазі, що в США їх більше, ніж ці чотири. Щоб охопити 50 держав в даний час, вам також потрібно буде додати посилання America/Phoenixна "US Mountain Standard Time", Pacific/Honoluluдо "Hawaiian Standard Time", America/Anchorageдо "Alaskan Standard Time"і America/Adakна "Aleutian Standard Time". Це не охоплює території США або історичні розбіжності, але почнете вам розпочати роботу.
Метт Джонсон-

2
Я б не рекомендував такий підхід, якщо наміром є охопити весь світ або мати справу з будь-яким дійсним ідентифікатором часового поясу. Список занадто довгий і занадто мінливий для цього.
Метт Джонсон-
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.