Come tradurre tra i fusi orari di Windows e IANA?


149

Come descritto nel wiki del fuso orario , esistono due diversi stili di fusi orari.

  • Quelli forniti da Microsoft per l'uso con Windows e la TimeZoneInfoclasse .Net (quando in esecuzione su Windows) sono identificati da un valore come "Eastern Standard Time".

  • Quelli forniti da IANA in TZDB e utilizzati dalla TimeZoneInfoclasse .NET durante l'esecuzione su Linux o OSX, sono identificati da un valore come "America/New_York".

Molte API basate su Internet utilizzano i fusi orari IANA, ma per numerosi motivi potrebbe essere necessario convertirlo in un ID di fuso orario di Windows o viceversa.

Come può essere realizzato in .Net?

Risposte:


198

La fonte primaria dei dati per la conversione tra identificatori di fuso orario Windows e IANA è il windowsZones.xmlfile, distribuito come parte del progetto CLDR Unicode . L'ultima versione di sviluppo può essere trovata qui .

Tuttavia , CLDR viene rilasciato solo due volte l'anno. Questo, insieme alla cadenza periodica degli aggiornamenti di Windows e agli aggiornamenti irregolari del database dei fusi orari IANA, rende complicato l'utilizzo diretto dei dati CLDR. Tieni presente che le modifiche del fuso orario vengono apportate per capriccio dei vari governi del mondo e non tutte le modifiche vengono apportate con sufficiente preavviso per entrare in questi cicli di rilascio prima delle rispettive date di validità.

Ci sono alcuni altri casi limite che devono essere gestiti che non sono coperti rigorosamente dal CLDR e di volta in volta ne compaiono di nuovi. Pertanto, ho incapsulato la complessità della soluzione nella micro-libreria TimeZoneConverter , che può essere installata da Nuget.

L'uso di questa libreria è semplice. Ecco alcuni esempi di conversione:

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"

Ci sono altri esempi sul sito del progetto .

È importante riconoscere che mentre un fuso orario IANA può essere mappato su un singolo fuso orario di Windows, non è vero il contrario. Un singolo fuso orario di Windows potrebbe essere associato a più di un fuso orario IANA. Questo può essere visto negli esempi sopra, dove Eastern Standard Timeè mappato su entrambi America/New_Yorke su America/Toronto. TimeZoneConverter fornirà quello contrassegnato da CLDR "001", noto come "zona aurea", a meno che non specifichi specificatamente un codice paese e che vi sia una corrispondenza per una zona diversa in quel paese.

Nota: questa risposta si è evoluta nel corso degli anni, quindi i commenti che seguono potrebbero o meno essere applicati alla revisione attuale. Rivedi la cronologia delle modifiche per i dettagli. Grazie.


1
utilizzando questo metodo per la conversione (GMT+05:30) Chennai, Kolkata, Mumbai, New DelhiAsia/Calcuttadovrebbe essere Asia/Kolkata. sembra che TzdbDateTimeZoneSourcecontenga vecchi valori.
Anto Subash,

1
@MattJohnson durante la conversione del metodo Asia/Kolkatausing IanaToWindows, non riesce. ma funziona con Asia/Calcuttaquale è il vecchio nome. Hai aggiornato il metodo WindowsToIanama IanaToWindowsha anche lo stesso problema. poche altre zone che non funzionano sono America/Argentina/Buenos_Aires, America/Indiana/Indianapolis, Asia/Kathmandu.
Anto Subash,

1
@AntoJSubash - Ancora una volta, ottima osservazione! Ho modificato il IanaToWindowsmetodo per compensare. Grazie mille!
Matt Johnson-Pint,

2
@MattJohnson I secondo @ osservazione di Sirrocco. Anche usare l'ID canonico come ha var canonical = tzdbSource.CanonicalIdMap[ ianaZoneId ]; links = Enumerable.Repeat( canonical, 1 ).Concat( links );fatto il trucco per me.
Johannes Rudolph,

2
@sirrocco - Mi dispiace non aver visto prima il tuo commento. Aggiornato le funzioni. Grazie!
Matt Johnson-Pint,

4

So che questa è una vecchia domanda, ma ho avuto un caso d'uso che avrei voluto condividere qui, poiché questo è il post più rilevante che ho trovato durante la ricerca. Stavo sviluppando un'app .NET Core usando un contenitore Linux docker, ma per la distribuzione su un server Windows. Quindi avevo solo bisogno del mio contenitore linux docker per supportare i nomi di fuso orario di Windows. Ho funzionato senza cambiare il mio codice dell'applicazione effettuando quanto segue:

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"

Quindi, nel mio codice .NET, il seguente ha funzionato senza alcuna modifica: TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")


1
Questo è un bel po 'fuori dagli schemi! Sembra che dovrebbe essere ok, purché tu stia coprendo alcuni fusi orari specifici. Tieni presente che ci sono più di quei quattro negli Stati Uniti. Per coprire i 50 stati ai giorni nostri, dovrai anche aggiungere collegamenti per America/Phoenixa "US Mountain Standard Time", Pacific/Honolulua "Hawaiian Standard Time", America/Anchoragea "Alaskan Standard Time"e America/Adaka "Aleutian Standard Time". Ciò non copre i territori statunitensi o le discrepanze storiche, ma ti farà iniziare.
Matt Johnson-Pint,

2
Non consiglierei questo approccio se il proprio intento è quello di coprire il mondo intero o trattare un identificatore di fuso orario valido. L'elenco è troppo lungo e troppo volatile per quello.
Matt Johnson-Pint,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.