DateTime.Now contre DateTime.UtcNow

225

Je me demandais quels sont exactement les principes de fonctionnement des deux propriétés. Je sais que le second est universel et ne traite essentiellement pas des fuseaux horaires, mais quelqu'un peut-il expliquer en détail comment ils fonctionnent et lequel devrait être utilisé dans quel scénario?

Slavo
la source
1
c'est peut-être trop tard mais je veux pointer vers ce blog: blog.angeloflogic.com/2013/10/…
Kai Wang
petit banc de repérage rextester.com/QRDR82396
Daniel B

Réponses:

346

DateTime.UtcNow vous indique la date et l'heure telles qu'elles seraient en temps universel coordonné, également appelé fuseau horaire de Greenwich Mean Time - essentiellement comme si vous étiez à Londres en Angleterre, mais pas pendant l'été. DateTime.Now donne la date et l'heure telles qu'elles apparaîtront à quelqu'un dans votre environnement local actuel.

Je recommanderais d'utiliser DateTime.Nowchaque fois que vous affichez une date à un être humain - de cette façon, ils sont à l'aise avec la valeur qu'ils voient - c'est quelque chose qu'ils peuvent facilement comparer à ce qu'ils voient sur leur montre ou leur horloge. À utiliser DateTime.UtcNowlorsque vous souhaitez stocker des dates ou les utiliser pour des calculs ultérieurs de cette façon (dans un modèle client-serveur) vos calculs ne deviennent pas confus par les clients dans des fuseaux horaires différents de votre serveur ou les uns des autres.

Blair Conrad
la source
84
un excellent point - lorsque vous stockez des dates dans une base de données ou un fichier, stockez-les définitivement en UTC!
Jeff Atwood,
15
Vous devez noter que lorsque vous souhaitez stocker des dates en UTC dans la base de données, vous devez vous assurer que la base de données n'ajoute pas son propre fuseau horaire aux dates qui ne donnent pas de fuseaux horaires explicites. Notez que DateTime utilisera toujours le fuseau horaire actuel lorsque demandé.
Omer van Kloeten
@OmervanKloeten donne un très bon point. Je me demande s'il existe une solution élégante et polyvalente pour cela, pour stocker et recevoir correctement les dates à chaque fois, même si votre serveur IIS et SQL sont dans des fuseaux horaires différents.
TheGeekZn
1
@ JoshYates1980 Oui, vous ne faites que DateTime.UtcNow.AddYears (1)
CathalMF
3
Utilisez NodaTime - cela vous obligera à penser au temps d'une manière plus utile et à éviter de tels problèmes
aateeque
86

C'est vraiment assez simple, donc je pense que cela dépend de ce que votre public est et où il vit.

Si vous n'utilisez pas Utc, vous devez connaître le fuseau horaire de la personne à laquelle vous affichez les dates et les heures - sinon vous lui direz que quelque chose s'est produit à 15 heures, heure du système ou du serveur, quand cela s'est vraiment produit à 17 heures, où ils vivent.

Nous l'utilisons DateTime.UtcNowparce que nous avons une audience Web mondiale et parce que je préfère ne pas harceler chaque utilisateur pour remplir un formulaire indiquant le fuseau horaire dans lequel il vit.

Nous affichons également des temps relatifs (il y a 2 heures, 1 jour, etc.) jusqu'à ce que le message vieillisse suffisamment pour que le temps soit "le même", peu importe où sur Terre vous vivez.

Jeff Atwood
la source
Je veux également savoir que le stockage de DateTime.UtcNow n'est également nécessaire que lorsque le calcul avec 2 dates est effectué pour obtenir les heures correctes. Quand je n'ai qu'à afficher une date RegisterAt, alors Datetime.Now est suffisant.
Elisabeth
36

Notez également la différence de performances; DateTime.UtcNowest quelque part environ 30 fois plus rapide alors DateTime.Now, car en interne, il DateTime.Nowfait beaucoup d'ajustements de fuseau horaire (vous pouvez facilement le vérifier avec Reflector).

Donc, NE PAS utiliser DateTime.Nowpour des mesures de temps relatif.

Magnus Krisell
la source
Cela m'a pris un voyage douloureux, sachez que UtcNow a de meilleures performances et que simplement enregistrer vos dates dans mysql et supposer que c'est utc et comparer les affichages dépendants de la date avec UtcNow simplifie ces problèmes de fuseau horaire mondial
Diin
29

Un concept principal de comprendre dans .NET est que maintenant est maintenant sur toute la terre , peu importe quel fuseau horaire vous êtes donc si vous chargez une variable. DateTime.NowOu DateTime.UtcNow-. L'affectation est identique * Votre DateTimeobjet sait ce que vous êtes en fuseau horaire et en tient compte quelle que soit la mission.

L'utilité de DateTime.UtcNowest pratique pour calculer les dates au-delà des limites de l'heure d'été. Autrement dit, dans les endroits qui participent à l'heure d'été, il y a parfois 25 heures de midi à midi le jour suivant, et parfois il y a 23 heures entre midi et midi le jour suivant. Si vous souhaitez déterminer correctement le nombre d'heures entre l'heure A et l'heure B, vous devez d'abord traduire chacune en leurs équivalents UTC avant de calculer le TimeSpan.

Ceci est couvert par un billet de blog que j'ai écrit qui explique plus en détail TimeSpanet comprend un lien vers un article MS encore plus complet sur le sujet.

* Clarification: chaque affectation stockera l'heure actuelle. Si vous deviez charger deux variables une via DateTime.Now()et l'autre via DateTime.UtcNow()la TimeSpandifférence entre les deux serait des millisecondes, pas des heures en supposant que vous êtes dans un fuseau horaire à des heures de GMT. Comme indiqué ci-dessous, l'impression de leurs Stringvaleurs afficherait différentes chaînes.

Appareil photo Carl
la source
1
Concernant "charger une variable avec DateTime.Now ou DateTime.UtcNow - l'affectation est identique": Cela peut-être besoin d'être clarifié? Comme je suis assis ici dans le fuseau horaire EDT (UTC -4), j'ai assigné deux variables à DateTime.UtcNow et DateTime.Now respectivement, puis j'ai imprimé leurs valeurs avec ToString (). Les valeurs affichées étaient à 4 heures d'intervalle - pas "identiques".
Jon Schneider
2
@ JonSchneider, je crois que vous avez raison. L'énoncé: «l'affectation est identique» n'est pas vrai. ToString () n'est probablement pas le meilleur moyen de tester cela, car il pourrait afficher des dates égales différemment (comme Java le fait). Les fonctions de comparaison sont un meilleur test et montrent qu'elles ne sont en effet pas égales.
Ted Bigham
Clarification de ma déclaration "identique": chargez une variable via DateTime.Now et une autre avec DateTime.UtcNow, puis imprimez la différence TimeSpan. La différence sera en millisecondes et non en heures en supposant que vous êtes à des heures de GMT.
Carl Camera
18

C'est une bonne question. Je le relance pour donner un peu plus de détails sur la façon dont .Net se comporte avec différentes Kindvaleurs. Comme le souligne @Jan Zich, il s'agit en fait d'une propriété extrêmement importante et définie différemment selon que vous utilisez Nowou UtcNow.

En interne, la date est stockée en tant Ticksque (contrairement à la réponse de @Carl Camera) est différente selon que vous utilisez Nowou UtcNow.

DateTime.UtcNowse comporte comme les autres langues. Il définit Ticksune valeur basée sur GMT. Il se met également Kindà Utc.

DateTime.Nowmodifie la Ticksvaleur à ce qu'elle serait si c'était votre heure dans le fuseau horaire GMT . Il se met également Kindà Local.

Si vous avez 6 heures de retard (GMT-6), vous obtiendrez l'heure GMT d'il y a 6 heures. .Net ignore Kindet traite cette fois comme si c'était il y a 6 heures, même si c'est censé être "maintenant". Cela se brise encore plus si vous créez une DateTimeinstance, puis modifiez votre fuseau horaire et essayez de l'utiliser.

Les instances DateTime avec différentes valeurs 'Kind' ne sont PAS compatibles.

Regardons un peu de code ...

    DateTime utc = DateTime.UtcNow;
    DateTime now = DateTime.Now;
    Debug.Log (utc + " " + utc.Kind);  // 05/20/2015 17:19:27 Utc
    Debug.Log (now + " " + now.Kind);  // 05/20/2015 10:19:27 Local

    Debug.Log (utc.Ticks);  // 635677391678617830
    Debug.Log (now.Ticks);  // 635677139678617840

    now = now.AddHours(1);
    TimeSpan diff = utc - now;
    Debug.Log (diff);  // 05:59:59.9999990

    Debug.Log (utc <  now);  // false
    Debug.Log (utc == now);  // false
    Debug.Log (utc >  now);  // true

    Debug.Log (utc.ToUniversalTime() <  now.ToUniversalTime());  // true
    Debug.Log (utc.ToUniversalTime() == now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() >  now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() -  now.ToUniversalTime());  // -01:00:00.0000010

Comme vous pouvez le voir ici, les comparaisons et les fonctions mathématiques ne sont pas automatiquement converties en heures compatibles. La Timespanaurait été presque une heure, mais était presque 6. « utc <maintenant » aurait dû être vrai (j'ai même ajouté une heure pour être sûr), mais était encore faux.

Vous pouvez également voir le «contourner» qui consiste simplement à convertir en temps universel n'importe où qui Kindn'est pas le même.

Ma réponse directe à la question est en accord avec la recommandation de la réponse acceptée sur le moment d'utiliser chacun. Vous devez toujours essayer de travailler avec des DateTimeobjets qui en ont Kind=Utc, sauf pendant les E / S (affichage et analyse). Cela signifie que vous devriez presque toujours l'utiliser DateTime.UtcNow, sauf dans les cas où vous créez l'objet juste pour l'afficher et le jeter immédiatement.

Ted Bigham
la source
7

DateTime n'a aucune idée des fuseaux horaires. Cela suppose toujours que vous êtes à l'heure locale. UtcNow signifie seulement "Soustraire mon fuseau horaire du temps".

Si vous souhaitez utiliser des dates sensibles au fuseau horaire, utilisez DateTimeOffset , qui représente une date / heure avec un fuseau horaire. J'ai dû l'apprendre à la dure.

Omer van Kloeten
la source
9
Pour être tout à fait précis (et éviter que les gens utilisent Now sur UtcNow pour des raisons de performances), c'est l'inverse: ajoute maintenant le fuseau horaire à UtcNow et est en fait d'une amplitude plus lente.
mafu
5

La réponse "simple" à la question est:

DateTime.Now renvoie une valeur DateTime représentant l'heure système actuelle (dans le fuseau horaire dans lequel le système s'exécute). La propriété DateTime.Kind sera DateTimeKind.Local

DateTime.UtcNow renvoie une valeur DateTime représentant l'heure coordonnée universelle actuelle (aka UTC) qui sera la même quel que soit le fuseau horaire du système. La propriété DateTime.Kind sera DateTimeKind.Utc

PapillonUK
la source
4

Juste un petit ajout aux remarques ci-dessus: la structure DateTime contient également un champ peu connu appelé Kind (du moins, je ne le savais pas depuis longtemps). Il s'agit simplement d'un indicateur indiquant si l'heure est locale ou UTC; il ne spécifie pas le décalage réel par rapport à UTC pour les heures locales. Outre le fait qu'il indique avec quelles intentions le stuct a été construit, il influence également le fonctionnement des méthodes ToUniversalTime () et ToLocalTime () .

Jan Zich
la source
1

DateTime.UtcNow est une échelle de temps continue à valeur unique, tandis que DateTime.Now n'est pas continue ou à valeur unique. La raison principale est l'heure d'été, qui ne s'applique pas à l'UTC. L'UTC ne saute donc ni en avant ni en arrière d'une heure, contrairement à l'heure locale (DateTime.Now). Et quand il saute en arrière, la même valeur de temps se produit deux fois.

user1315023
la source
1

DateTime.UtcNow est une échelle de temps universelle omettant l'heure d'été. L'UTC ne change donc jamais en raison de l'heure d'été.

Mais, DateTime.Now n'est pas continu ou à valeur unique car il change en fonction de l'heure d'été. Ce qui signifie DateTime.Now, la même valeur d'heure peut se produire deux fois, laissant les clients dans un état confus.

ChaiVan
la source
0

Lorsque vous avez besoin d'une heure locale pour la machine sur laquelle votre application s'exécute (comme CEST pour l'Europe), utilisez Now. Si vous voulez un temps universel - UtcNow. C'est juste une question de vos préférences - créer probablement un site Web local / une application autonome que vous souhaitez utiliser le temps que l'utilisateur a - donc affecté par son paramètre de fuseau horaire - DateTime.Now.

N'oubliez pas, pour un site Web, c'est le réglage du fuseau horaire du serveur. Donc, si vous affichez l'heure pour l'utilisateur, obtenez son fuseau horaire préféré et décalez l'heure (enregistrez simplement l'heure Utc dans la base de données, puis modifiez-la) ou spécifiez son UTC. Si vous oubliez de le faire, l'utilisateur peut voir quelque chose comme: posté il y a 3 minus puis un temps dans le futur proche :)

kender
la source
0

La grande différence :) est que DateTime.Now n'est pas pris en charge dans le flux de travail SharePoint, vous devez utiliser DateTime.UtcNow

Michel LAPLANE
la source