Wie übersetze ich zwischen Windows- und IANA-Zeitzonen?

149

Wie im Zeitzonen-Tag-Wiki beschrieben , gibt es zwei verschiedene Arten von Zeitzonen.

  • Diejenigen, die von Microsoft zur Verwendung mit Windows und der .Net- TimeZoneInfoKlasse (unter Windows) bereitgestellt werden, werden durch einen Wert wie z "Eastern Standard Time".

  • Diejenigen, die von IANA in der TZDB bereitgestellt und von der .NET- TimeZoneInfoKlasse unter Linux oder OSX verwendet werden, werden durch einen Wert wie z "America/New_York".

Viele internetbasierte APIs verwenden die IANA-Zeitzonen, aber aus zahlreichen Gründen muss dies möglicherweise in eine Windows-Zeitzonen-ID konvertiert werden oder umgekehrt.

Wie kann dies in .Net erreicht werden?

Matt Johnson-Pint
quelle

Antworten:

198

Die Hauptquelle für die Daten zur Konvertierung zwischen Windows- und IANA-Zeitzonen-IDs ist die windowsZones.xmlDatei, die im Rahmen des Unicode CLDR- Projekts verteilt wird. Die neueste Entwicklerversion finden Sie hier .

Allerdings wird CLDR nur zweimal jährlich veröffentlicht. Dies, zusammen mit der periodischen Trittfrequenz von Windows-Updates und den unregelmäßigen Updates der IANA-Zeitzonendatenbank, macht es kompliziert, nur die CLDR-Daten direkt zu verwenden. Beachten Sie, dass Zeitzonenänderungen selbst nach Lust und Laune der verschiedenen Regierungen der Welt vorgenommen werden und nicht alle Änderungen mit ausreichender Ankündigung vorgenommen werden, um in diese Veröffentlichungszyklen vor ihrem jeweiligen Inkrafttreten zu gelangen.

Es müssen einige andere Randfälle behandelt werden, die nicht ausschließlich von der CLDR abgedeckt werden, und von Zeit zu Zeit tauchen neue auf. Daher habe ich die Komplexität der Lösung in die TimeZoneConverter -Mikrobibliothek eingekapselt, die von Nuget aus installiert werden kann.

Die Verwendung dieser Bibliothek ist einfach. Hier einige Beispiele für die Konvertierung:

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"

Weitere Beispiele finden Sie auf der Projektseite .

Es ist wichtig zu erkennen, dass eine IANA-Zeitzone zwar einer einzelnen Windows-Zeitzone zugeordnet werden kann, das Gegenteil jedoch nicht der Fall ist. Eine einzelne Windows-Zeitzone kann mehreren IANA-Zeitzonen zugeordnet sein. Dies ist in den obigen Beispielen zu sehen, in denen Eastern Standard Timesowohl auf America/New_Yorkals auch auf abgebildet ist America/Toronto. TimeZoneConverter liefert diejenige, mit der CLDR markiert ist "001", die als "goldene Zone" bezeichnet wird, es sei denn, Sie geben speziell einen Ländercode an und es gibt eine Übereinstimmung für eine andere Zone in diesem Land.

Hinweis: Diese Antwort hat sich im Laufe der Jahre weiterentwickelt, sodass die folgenden Kommentare möglicherweise für die aktuelle Version gelten oder nicht. Überprüfen Sie den Bearbeitungsverlauf auf Details. Vielen Dank.

Matt Johnson-Pint
quelle
1
mit dieser Methode bei der Konvertierung (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhigibt Asia/Calcuttaes sein sollte Asia/Kolkata. es scheint, als ob das TzdbDateTimeZoneSourcealte Werte enthält.
Anto Subash
1
@MattJohnson beim Konvertieren der Asia/Kolkatausing- IanaToWindows Methode schlägt dies fehl. aber es funktioniert mit Asia/Calcuttadem alten Namen. Sie haben die Methode aktualisiert, haben WindowsToIanaaber IanaToWindowsauch das gleiche Problem. einige andere Zonen , die nicht berufstätig sind sind America/Argentina/Buenos_Aires, America/Indiana/Indianapolis, Asia/Kathmandu.
Anto Subash
1
@AntoJSubash - Wieder eine tolle Beobachtung! Ich habe die IanaToWindowsMethode zum Ausgleich bearbeitet . Vielen Dank!
Matt Johnson-Pint
2
@MattJohnson Ich stimme der Beobachtung von @ Sirrocco zu. Die kanonische ID zu verwenden, var canonical = tzdbSource.CanonicalIdMap[ ianaZoneId ]; links = Enumerable.Repeat( canonical, 1 ).Concat( links );hat mir auch geholfen.
Johannes Rudolph
2
@ Sirrocco - Entschuldigung, ich habe Ihren Kommentar nicht früher gesehen. Die Funktionen wurden aktualisiert. Vielen Dank!
Matt Johnson-Pint
4

Ich weiß, dass dies eine alte Frage ist, aber ich hatte einen Anwendungsfall, den ich hier teilen möchte, da dies der relevanteste Beitrag ist, den ich bei der Suche gefunden habe. Ich habe eine .NET Core-App mit einem Docker-Linux-Container entwickelt, aber für die Bereitstellung auf einem Windows-Server. Daher brauchte ich nur meinen Docker-Linux-Container, um die Windows-Zeitzonennamen zu unterstützen. Ich habe dies zum Laufen gebracht, ohne meinen Anwendungscode zu ändern, indem ich Folgendes getan habe:

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"

In meinem .NET-Code funktionierte Folgendes wie folgt: TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")

Immer präsent
quelle
1
Das ist ein ziemlich gutes Out-of-the-Box-Denken! Dies scheint in Ordnung zu sein, solange Sie einige bestimmte Zeitzonen abdecken. Denken Sie daran, dass es in den USA mehr als diese vier gibt. Um die 50 Staaten der Gegenwart abzudecken, müssen Sie auch Links für America/Phoenixto "US Mountain Standard Time", Pacific/Honoluluto "Hawaiian Standard Time", America/Anchorageto "Alaskan Standard Time"und America/Adakto hinzufügen "Aleutian Standard Time". Das deckt keine US-Territorien oder historischen Diskrepanzen ab, aber es wird Ihnen den Einstieg erleichtern.
Matt Johnson-Pint
2
Ich würde diesen Ansatz nicht empfehlen, wenn man die ganze Welt abdecken oder sich mit einer gültigen Zeitzonen-ID befassen möchte. Die Liste ist dafür zu lang und zu volatil.
Matt Johnson-Pint