web-dev-qa-db-fra.com

Comment fonctionne DateTime.ToUniversalTime ()?

Comment fonctionne la conversion en UTC du format DateTime standard?

Plus précisément, si je crée un objet DateTime dans un fuseau horaire et que je passe ensuite à un autre fuseau horaire et que j'exécute ToUniversalTime(), comment sait-il que la conversion a été effectuée correctement et que l'heure est toujours représenté avec précision?

61
derGral

Aucun fuseau horaire implicite n'est attaché à un objet DateTime. Si vous exécutez ToUniversalTime() sur, il utilise le fuseau horaire du contexte que le code est en cours d'exécution en.

Par exemple, si je crée un DateTime à partir de l'époque du 1/1/1970, cela me donne le même objet DateTime, peu importe où je suis dans le monde.

Si je cours ToUniversalTime() sur quand je suis en cours d'exécution du code à Greenwich, je reçois en même temps. Si je le fais pendant que je vis à Vancouver, je reçois un objet décalé DateTime -8 heures.

Voilà pourquoi il est important de temps stocker des informations connexes dans votre base de données temps UTC lorsque vous devez faire une sorte de conversion ou de localisation jour. Considérez si votre base de code a été déplacée vers une installation serveur dans un autre fuseau horaire;)

Edit: note de la réponse de Joel - objets DateTime par défaut sont typés comme DateTimeKind.Local. Si vous analysez une date et définir comme DateTimeKind.Utc, Puis ToUniversalTime() N'a pas de conversion.

Et voici un article sur "Best Practices Coding with Date Times" , et un article sur Conversion DateTimes with .Net .

71
womp

Tout d'abord, il vérifie si l'on sait Kind du DateTime pour être UTC déjà. Si c'est le cas, il renvoie la même valeur.

Dans le cas contraire, il est supposé être une heure locale - qui est local à l'ordinateur, il fonctionne sur, et en particulier dans le fuseau horaire que l'ordinateur utilisait quand une propriété privée a été paresseusement initialisé. Cela signifie que si vous modifiez le fuseau horaire après le démarrage de votre application, il y a de fortes chances qu'elle utilise toujours l'ancien.

Le fuseau horaire contient suffisamment d'informations pour convertir une heure locale en heure UTC ou vice versa, bien qu'il y ait des moments ambigus ou invalides. (Il y a des heures locales qui se produisent deux fois et des heures locales qui ne se produisent jamais en raison de l'heure d'été.) Les règles de traitement de ces cas sont spécifiées dans la documentation :

Si la valeur d'instance de date et d'heure est une heure ambiguë, cette méthode suppose qu'il s'agit d'une heure standard. (Un temps ambigu est celui qui peut la carte soit à une heure normale ou à un gain de temps de la lumière du jour dans la zone heure locale) Si la date et la valeur de l'instance le temps est un temps non valide, cette méthode retranche simplement l'heure locale des années de fuseau horaire locale Décalage UTC pour retourner UTC. (Une heure non valide est une heure qui n'existe pas en raison de l'application des règles d'ajustement de l'heure d'été.)

La valeur retournée aura un Kind de DateTimeKind.Utc, Donc si vous appelez ToUniveralTime, cela n'appliquera plus le décalage. (Il s'agit d'une amélioration considérable par rapport à .NET 1.1!)

Si vous voulez un fuseau horaire non local, vous devez utiliser TimeZoneInfo qui a été introduit dans .NET 3.5 (il existe des solutions hacky pour les versions antérieures, mais elles ' re pas Nice). Pour représenter un instant dans le temps, vous devez envisager d'utiliser DateTimeOffset qui a été introduit dans .NET 2.0SP1, .NET3.0SP1 et .NET 3.5. Toutefois, cela n'a pas encore une zone de temps réel associé - juste un décalage par rapport à UTC. Cela signifie que vous ne savez pas quelle heure locale sera une heure plus tard, par exemple - les règles DST peuvent varier entre les fuseaux horaires qui se sont avérés utiliser le même décalage pour cet instant particulier. TimeZoneInfo est conçu pour tenir compte des règles historiques et futures, par opposition à TimeZone qui est quelque peu simpliste.

Fondamentalement, la prise en charge dans .NET 3.5 est bien meilleure qu'elle ne l'était, mais laisse toujours à désirer pour une arithmétique de calendrier appropriée. Quelqu'un a envie de porter Joda Time vers .NET? ;)

34
Jon Skeet

What @ womp said , avec l'ajout qu'il vérifie la propriété Kind de DateTime pour voir si elle peut déjà être une date UTC .

7
Joel Coehoorn

DateTime.ToUniversalTime supprime le décalage de fuseau horaire du fuseau horaire local pour normaliser un DateTime à UTC. Si vous utilisez ensuite DateTime.ToLocalTime sur la valeur normalisée dans un autre fuseau horaire, le décalage de fuseau horaire de ce fuseau horaire sera ajouté à la valeur normalisée pour une représentation correcte dans ce fuseau horaire.

3