Comment fonctionne DateTime.ToUniversalTime ()?
Question
Comment fonctionne la conversion en UTC du format standard DateTime
?
Plus précisément, si je crée un objet DateTime
dans un fuseau horaire, puis passe à un autre fuseau horaire et exécute ToUniversalTime ()
, comment connaît-il le la conversion a été effectuée correctement et que le temps est toujours représenté avec précision?
La solution
Il n'y a pas de fuseau horaire implicite associé à un objet DateTime
. Si vous exécutez ToUniversalTime ()
, le fuseau horaire du contexte dans lequel le code est exécuté est utilisé.
Par exemple, si je crée un DateTime
depuis l'époque du 1/1/1970, le même objet DateTime
me sera délivré, où que je sois dans le monde. .
Si j'exécute ToUniversalTime ()
lorsque j'exécute le code à Greenwich, le temps est identique. Si je le fais alors que j'habite à Vancouver, j'obtiens un objet DateTime
offset de -8 heures.
C’est pourquoi il est important de stocker les informations relatives à l’heure dans votre base de données sous forme d’heures UTC lorsque vous devez effectuer tout type de conversion ou de localisation de date. Déterminez si votre base de code a été déplacée vers un serveur dans un autre fuseau horaire;)
Éditer: note de la réponse de Joel - Les objets DateTime
sont saisis par défaut sous la forme DateTimeKind.Local
. Si vous analysez une date et la définissez comme DateTimeKind.Utc
, ToUniversalTime ()
n'effectue aucune conversion.
Et voici un article sur le "Codage des meilleures pratiques avec la date et l'heure" et un article sur la Conversion de DateTimes avec .Net .
Autres conseils
Tout d'abord, il vérifie si le Kind
du DateTime
est déjà connu pour être UTC. Si tel est le cas, la même valeur est renvoyée.
Sinon, l'heure locale est supposée être locale, c'est-à-dire locale pour l'ordinateur sur lequel il est exécuté, et en particulier pour le fuseau horaire utilisé par l'ordinateur lors de l'initialisation initiale d'une propriété privée. Cela signifie que si vous modifiez le fuseau horaire après le démarrage de votre application, il y a de bonnes chances qu'il utilise toujours l'ancien.
Le fuseau horaire contient suffisamment d’informations pour convertir une heure locale en une heure UTC ou inversement, bien que cela puisse parfois être ambigu ou invalide. (Il existe des heures locales qui se produisent deux fois et d'autres qui ne se produisent jamais en raison de l'heure avancée.) Les règles de traitement de ces cas sont spécifiées dans la documentation :
Si la valeur de l'instance de date et heure est un temps ambigu, cette méthode suppose que c'est un temps standard. (Un temps ambigu est celui qui peut cartographier soit à une heure normale ou à un heure d'été selon l'heure locale zone) Si l'instance de date et heure la valeur est une heure invalide, cette méthode soustrait simplement l'heure locale de décalage UTC du fuseau horaire local à retourner UTC. (Un temps invalide est un cela n'existe pas à cause de la application de l'heure d'été règles de réglage.)
La valeur renvoyée aura un type
de DateTimeKind.Utc
. Par conséquent, si vous appelez ToUniveralTime
, le décalage ne sera pas appliqué. encore. (Il s'agit d'une amélioration considérable par rapport à .NET 1.1!)
Si vous souhaitez un fuseau horaire non local, vous devez utiliser < code> TimeZoneInfo qui a été introduit dans .NET 3.5 (il existe des solutions pour hacky pour les versions antérieures, mais elles ne sont pas agréables). Pour représenter un instant dans le temps, vous devez envisager d'utiliser DateTimeOffset
introduit dans .NET 2.0SP1, .NET3.0SP1 et .NET 3.5. Cependant, aucun fuseau horaire n’est associé à cela - il n’ya qu’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 pour lesquels le même décalage a été utilisé pour cet instant particulier. TimeZoneInfo
est conçu pour prendre en compte les règles historiques et futures, par opposition à TimeZone
, ce qui est quelque peu simpliste.
Fondamentalement, la prise en charge de .NET 3.5 est bien meilleure qu’elle ne l’était, mais laisse tout de même quelque chose à désirer pour une arithmétique appropriée du calendrier. Quelqu'un souhaite-t-il transférer Joda Time vers .NET? ;)
Ce que @womp a déclaré , en ajoutant qu'il vérifie la propriété Kind de DateTime pour voir si elle peut déjà être une date UTC.
DateTime.ToUniversalTime supprime le décalage de fuseau horaire du fuseau horaire local pour normaliser un DateTime en 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.