Quelle est la différence entre DateTime.ToUniversalTime et TimeZoneInfo.ConvertTimeToUtc

StackOverflow https://stackoverflow.com/questions/1704780

  •  19-09-2019
  •  | 
  •  

Question

Je viens juste de commencer à penser correctement au sujet de déploiement d'une webapp qui devra faire des choses pour les utilisateurs au début de leur journée, disons 6h du matin. À la fin de leurs jours.

Partout où j'ai lu au sujet des gens qui disent beaucoup juste à utiliser .ToUniversalTime pour stocker l'heure UTC, mais quand j'ai essayé ceci (comme je le soupçonnais) il ne fonctionne pas, et il vient déplacé le temps sur par une heure (je suis au Royaume-Uni, donc je pensais que cela devait faire avec décalage par rapport à GMT à UTC, bien que cela n'a pas de sens pour moi, comme l'économie de la lumière du jour doit être éteint au moment).

J'ai un champ dans la db qui stocke le fuseau horaire des utilisateurs, et donc quand je commencé à utiliser ConvertTimeToUtc et fromUtc, il a commencé à faire ce que je m'y attendais pas à le faire. Bien qu'encore une fois je ne suis pas sûr si je dois construire dans une logique moi-même à faire des conversions d'économie de la lumière du jour, ou il devrait le faire pour moi.

Je suis surtout demandé pourquoi tout le monde parlait .ToUniversalTime, car il ne semble vraiment pas me aider, et je ne pouvais pas comprendre comment il pouvait savoir à quel point pour compenser le temps de passer à UTC, alors que la seconde voie un sens.

Quelqu'un pourrait-il expliquer comment chaque méthode pourrait être utile?

Était-ce utile?

La solution

Si vous exécutez le code sur une machine dans un fuseau horaire différent, vos calculs vont encore travailler? Ceci est la raison des gens stocker et traiter tous les DateTimes comme UTC - il supprime toute ambiguïté. Vous auriez pas besoin de stocker le fuseau horaire de l'utilisateur. Toute machine, n'importe où, peut tirer une date à partir de la base de données et le convertir en provenance et à l'heure locale avec la facilité.

Si vous stockez fois dans un autre fuseau horaire, alors vous devez tirer sur, calculer le décalage du fuseau horaire souhaité, y compris l'affacturage en temps d'épargne de jour et de considérations Dateline internationales. Dans votre cas, vous stockez également des informations inutiles supplémentaires.

Autres conseils

Il fait une différence entre ces deux.

Dans .NET 3.5 et inférieur , Datetime.ToUniversalTime est implémenté comme:

public DateTime ToUniversalTime() {
    return TimeZone.CurrentTimeZone.ToUniversalTime(this);
}

Parce qu'il utilise la classe TimeZone, il a subi les mêmes problèmes mentionnés dans la documentation MSDN :

  

La classe TimeZone prend en charge une seule règle d'ajustement du temps de l'heure d'été pour le fuseau horaire local. En conséquence, la classe TimeZone peut signaler avec précision les informations de temps d'économie de jour ou de convertir entre l'UTC et l'heure locale que pour la période où la dernière règle d'ajustement est en vigueur. En revanche, la classe TimeZoneInfo prend en charge les règles d'ajustement multiples, ce qui permet de travailler avec des données de fuseau horaire historique.

Dans .NET 4.0 et versions ultérieures , Datetime.ToUniversalTime est implémenté comme:

public DateTime ToUniversalTime() { 
    return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
} 

résout le problème de ne pas soutenir les règles d'ajustement historiques, mais en raison du drapeau NoThrowOnInvalidTime, il est pas la même comme juste appeler TimeZoneInfo.ConvertimeToUtc.

La méthode qu'il appelle est un interne surcharge de ConvertTimeToUtc qui prend un drapeau TimeZoneInfoOptions. publique version de la méthode utilise TimeZoneInfoOptions.None, alors que celui-ci utilise TimeZoneInfoOptions.NoThrowOnInvalidTime.

La différence peut être illustrée comme suit. Avec le fuseau horaire défini à heure du Pacifique:

DateTime dt = new DateTime(2015, 3, 8, 2, 0, 0, DateTimeKind.Local);
DateTime utc = dt.ToUniversalTime();
Console.WriteLine(utc); // "3/8/2015 10:00:00 AM"

Vs:

DateTime dt = new DateTime(2015, 3, 8, 2, 0, 0, DateTimeKind.Local);
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt);  // throws exception!
Console.WriteLine(utc);

Depuis cette date, dans ce fuseau horaire, le temps saute 1:59:59-03:00:00, fournit une heure locale de 2:00:00 est pas valide. La bonne chose à faire est de lancer une exception (comme dans le second cas). Toutefois, étant donné le contrat existant de DateTime.ToUniversalTime des versions-cadres précédents n'a pas permis cela, le cadre choisit de retourner une valeur au lieu de jeter.

La valeur de son choix est calculée sur la base en utilisant la temps standard décalage, comme si la transition DST n'a pas eu lieu.

Edit: je me trompais. Voir répondre pour une explication des différences subtiles entre les implémentations de DateTime.ToUniversalTime et TimeZoneInfo.ConvertTimeToUtc.

Pour toute autre personne qui a la question spécifique formulée dans le titre: Quelle est la différence entre DateTime.ToUniversalTime et TimeZoneInfo.ConvertTimeToUtc

La réponse est:. Il n'y a pas de différence

Utilisation JustDecompile pour inspecter la mise en œuvre de DateTime.ToUniversalTime dans .NET 4.5, nous voyons qu'il utilise directement TimeZoneInfo.ConvertTimeToUtc:

    public DateTime ToUniversalTime()
    {
        return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top