Comment traduire entre les fuseaux horaires Windows et IANA?

149

Comme décrit dans le wiki des balises de fuseau horaire , il existe deux styles de fuseaux horaires différents.

  • Ceux fournis par Microsoft pour une utilisation avec Windows et la TimeZoneInfoclasse .Net (lors de l'exécution sous Windows) sont identifiés par une valeur telle que "Eastern Standard Time".

  • Ceux fournis par l'IANA dans le TZDB et utilisés par la TimeZoneInfoclasse .NET lors de l'exécution sous Linux ou OSX sont identifiés par une valeur telle que "America/New_York".

De nombreuses API basées sur Internet utilisent les fuseaux horaires IANA, mais pour de nombreuses raisons, il peut être nécessaire de le convertir en un identifiant de fuseau horaire Windows, ou vice-versa.

Comment cela peut-il être accompli dans .Net?

Matt Johnson-Pint
la source

Réponses:

198

La source principale des données pour la conversion entre les identificateurs de fuseau horaire Windows et IANA est le windowsZones.xmlfichier, distribué dans le cadre du projet Unicode CLDR . La dernière version de développement peut être trouvée ici .

Cependant , le CLDR n'est publié que deux fois par an. Ceci, associé à la cadence périodique des mises à jour Windows et aux mises à jour irrégulières de la base de données de fuseaux horaires IANA, complique l'utilisation directe des données CLDR. Gardez à l'esprit que les changements de fuseau horaire eux-mêmes sont effectués au gré des différents gouvernements du monde, et que tous les changements ne sont pas effectués avec un préavis suffisant pour en faire ces cycles de publication avant leurs dates d'entrée en vigueur respectives.

Il y a quelques autres cas extrêmes qui doivent être traités qui ne sont pas strictement couverts par le CLDR, et de nouveaux surgissent de temps en temps. Par conséquent, j'ai encapsulé la complexité de la solution dans la micro-bibliothèque TimeZoneConverter , qui peut être installée à partir de Nuget.

L'utilisation de cette bibliothèque est simple. Voici quelques exemples de conversion:

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"

Il y a plus d'exemples sur le site du projet .

Il est important de reconnaître que si un fuseau horaire IANA peut être mappé à un seul fuseau horaire Windows, l'inverse n'est pas vrai. Un seul fuseau horaire Windows peut être mappé à plusieurs fuseaux horaires IANA. Cela peut être vu dans les exemples ci-dessus, oùEastern Standard Time est mappé à la fois America/New_Yorket à America/Toronto. TimeZoneConverter fournira celui avec lequel CLDR marque "001", connu sous le nom de "zone dorée", à moins que vous ne fournissiez spécifiquement un code de pays et qu'il y ait une correspondance pour une zone différente dans ce pays.

Remarque: Cette réponse a évolué au fil des ans, de sorte que les commentaires ci-dessous peuvent s'appliquer ou non à la révision actuelle. Consultez l'historique des modifications pour plus de détails. Merci.

Matt Johnson-Pint
la source
1
en utilisant cette méthode lors de la conversion (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhidonne Asia/Calcuttaqu'il devrait être Asia/Kolkata. il semble que le TzdbDateTimeZoneSourcecontient d'anciennes valeurs.
Anto Subash
1
@MattJohnson lors de la conversion de la méthode Asia/Kolkatausing IanaToWindows, cela échoue. mais cela fonctionne avec Asia/Calcuttaquel est l'ancien nom. Vous avez mis à jour la méthode WindowsToIanamais vous rencontrez IanaToWindowségalement le même problème. quelques autres zones qui ne fonctionnent pas sont America/Argentina/Buenos_Aires, America/Indiana/Indianapolis, Asia/Kathmandu.
Anto Subash
1
@AntoJSubash - Encore une fois, bonne observation! J'ai édité la IanaToWindowsméthode pour compenser. Merci beaucoup!
Matt Johnson-Pint
2
@MattJohnson Je seconde l'observation de @ sirrocco. L'utilisation de l'identifiant canonique a également var canonical = tzdbSource.CanonicalIdMap[ ianaZoneId ]; links = Enumerable.Repeat( canonical, 1 ).Concat( links );fait l'affaire pour moi.
Johannes Rudolph
2
@sirrocco - Désolé, je n'ai pas vu votre commentaire plus tôt. Mise à jour des fonctions. Merci!
Matt Johnson-Pint
4

Je sais que c'est une vieille question, mais j'avais un cas d'utilisation que je pensais partager ici, car c'est le message le plus pertinent que j'ai trouvé lors de la recherche. Je développais une application .NET Core à l'aide d'un conteneur Linux Docker, mais pour un déploiement sur un serveur Windows. Je n'avais donc besoin que de mon conteneur Linux Docker pour prendre en charge les noms de fuseau horaire Windows. J'ai fait fonctionner cela sans changer le code de mon application en procédant comme suit:

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"

Ensuite, dans mon code .NET, ce qui suit a fonctionné sans aucune modification: TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")

EverPresent
la source
1
C'est une très bonne réflexion hors de la boîte! Cela semble correct, tant que vous couvrez quelques fuseaux horaires spécifiques. Gardez à l'esprit qu'il y en a plus que ces quatre aux États-Unis. Pour couvrir les 50 états actuels, vous devrez également ajouter des liens America/Phoenixvers "US Mountain Standard Time", Pacific/Honoluluvers "Hawaiian Standard Time", America/Anchoragevers "Alaskan Standard Time"et America/Adakvers "Aleutian Standard Time". Cela ne couvre pas les territoires américains ou les écarts historiques, mais vous aidera à démarrer.
Matt Johnson-Pint
2
Je ne recommanderais pas cette approche si l'intention est de couvrir le monde entier ou de traiter un identifiant de fuseau horaire valide. La liste est trop longue et trop volatile pour cela.
Matt Johnson-Pint