DateTime.Now vs. DateTime.UtcNow

225

Zastanawiałem się, jakie dokładnie są zasady działania tych dwóch właściwości. Wiem, że drugi jest uniwersalny i zasadniczo nie zajmuje się strefami czasowymi, ale czy ktoś może szczegółowo wyjaśnić, jak działają i który z nich należy zastosować w jakim scenariuszu?

Slavo
źródło
1
może być za późno, ale chcę wskazać na tego bloga: blog.angeloflogic.com/2013/10/…
Kai Wang
mały benchmarking rextester.com/QRDR82396
Daniel B

Odpowiedzi:

346

DateTime.UtcNow podaje datę i godzinę, tak jak w uniwersalnym czasie koordynowanym, który jest również nazywany strefą czasową średniego czasu Greenwich - w zasadzie tak, jakbyś był w Londynie w Anglii, ale nie latem. DateTime.Now podaje datę i godzinę, tak jak wyglądałoby to dla kogoś w twoim bieżącym języku.

Polecam używać, DateTime.Nowgdy wyświetlasz randkę człowiekowi - w ten sposób czują się komfortowo z wartością, którą widzą - jest to coś, co mogą łatwo porównać z tym, co widzą na zegarku lub zegarze. Użyj, DateTime.UtcNowgdy chcesz zapisać daty lub użyć ich do późniejszych obliczeń w ten sposób (w modelu klient-serwer) Twoje obliczenia nie będą mylone przez klientów w różnych strefach czasowych od twojego serwera lub od siebie nawzajem.

Blair Conrad
źródło
84
doskonały punkt - kiedy przechowujesz daty w bazie danych lub pliku, zdecydowanie przechowuj je w UTC!
Jeff Atwood,
15
Musisz pamiętać, że jeśli chcesz przechowywać daty w UTC w bazie danych, musisz upewnić się, że baza danych nie dodaje własnej strefy czasowej do dat, które nie zawierają wyraźnych stref czasowych. Pamiętaj, że DateTime zawsze będzie używał bieżącej strefy czasowej, gdy zostanie o to poproszony.
Omer van Kloeten,
@OmervanKloeten daje bardzo dobry punkt. Zastanawiam się, czy istnieje eleganckie, wszechstronne rozwiązanie do przechowywania i odbierania dat za każdym razem, nawet jeśli IIS i serwer SQL znajdują się w różnych strefach czasowych.
TheGeekZn
1
@ JoshYates1980 Tak, po prostu wykonujesz DateTime.UtcNow.AddYears (1)
CathalMF
3
Skorzystaj z NodaTime - zmusi Cię to do myślenia w bardziej użyteczny sposób i
pozwoli
86

To naprawdę dość proste, więc myślę, że zależy to od tego, kim są twoi odbiorcy i gdzie mieszkają.

Jeśli nie używasz Utc, musisz znać strefę czasową osoby, dla której wyświetlasz daty i godziny - w przeciwnym razie powiesz im, że coś się wydarzyło o godzinie 15:00 w czasie systemowym lub na serwerze, a tak naprawdę stało się o godzinie 17:00, gdzie zdarzają się żyć.

Korzystamy z tego, DateTime.UtcNowponieważ mamy globalną publiczność internetową, a ponieważ wolałbym nie nakłaniać każdego użytkownika do wypełnienia formularza wskazującego strefę czasową, w której żyją.

Wyświetlamy także czasy względne (2 godziny temu, 1 dzień temu itp.), Dopóki post nie zestarzeje się wystarczająco, aby czas był „taki sam”, bez względu na to, gdzie mieszkasz na Ziemi.

Jeff Atwood
źródło
Chcę również po drugie, aby przechowywać DateTime.UtcNow jest również potrzebne tylko wtedy, gdy obliczenia z 2 datami są wykonane, aby uzyskać prawidłowe godziny. Kiedy muszę tylko wyświetlić datę rejestracji, to Datetime.Teraz wystarczy.
Elisabeth
36

Zwróć także uwagę na różnicę wydajności; DateTime.UtcNowjest gdzieś około 30 razy szybszy DateTime.Now, ponieważ wewnętrznie DateTime.Nowwykonuje wiele regulacji strefy czasowej (można to łatwo zweryfikować za pomocą Odbłyśnika).

Dlatego NIE używaj DateTime.Nowdo pomiaru czasu względnego.

Magnus Krisell
źródło
Zabrało mnie bolesna podróż, po prostu wiem, że UtcNow ma lepszą wydajność, a po prostu zapisywanie dat w mysql i zakładanie, że jest to utc i porównywanie wyświetlaczy zależnych od daty z UtcNow upraszcza globalne problemy ze strefą czasową
Diin
29

Jedną z głównych koncepcji, które należy zrozumieć w .NET jest to, że teraz jest teraz na całej Ziemi, bez względu na strefę czasową, w której się znajdujesz. Więc jeśli załadujesz zmienną przy pomocy DateTime.Nowlub DateTime.UtcNow- przypisanie jest identyczne. * Twój DateTimeobiekt wie, w której strefie czasowej się znajdujesz i bierze to pod uwagę niezależnie od zadania.

Przydatność DateTime.UtcNowprzydaje się przy obliczaniu dat w granicach czasu letniego. Oznacza to, że w miejscach, które uczestniczą w czasie letnim, czasami jest 25 godzin od południa do południa następnego dnia, a czasem są 23 godziny między południem a południem następnego dnia. Jeśli chcesz poprawnie określić liczbę godzin od czasu A i czasu B, musisz najpierw przeliczyć każdy z nich na ich odpowiedniki UTC przed obliczeniem TimeSpan.

Jest to objęte postem na blogu, który napisałem, który wyjaśnia TimeSpani zawiera link do jeszcze obszerniejszego artykułu na ten temat.

* Wyjaśnienie: Każde przypisanie zapisze bieżący czas. Jeśli było ładować za pomocą dwóch zmiennych jedną DateTime.Now()a drugą za pośrednictwem DateTime.UtcNow()tej TimeSpanróżnicy między nimi byłaby milisekund, a nie godzin zakładając, że jesteś ze strefy czasowej godziny od GMT. Jak zauważono poniżej, wydrukowanie ich Stringwartości spowoduje wyświetlenie różnych ciągów.

Carl Camera
źródło
1
Odnośnie „załaduj zmienną za pomocą DateTime.Now lub DateTime.UtcNow - przypisanie jest identyczne”: Może to wymagać wyjaśnienia? Siedząc tutaj w strefie czasowej EDT (UTC -4), przypisałem dwie zmienne odpowiednio do DateTime.UtcNow i DateTime.Now, a następnie wydrukowałem ich wartości za pomocą ToString (). Wyświetlane wartości były w odstępie 4 godzin - nie „identyczne”.
Jon Schneider
2
@JonSchneider, uważam, że masz rację. Stwierdzenie: „przypisanie jest identyczne” nie jest prawdziwe. ToString () nie jest prawdopodobnie najlepszym sposobem na przetestowanie tego, ponieważ może wyświetlać równe daty inaczej (podobnie jak Java). Funkcje porównania są lepszym testem i pokazują, że faktycznie nie są sobie równe.
Ted Bigham,
Wyjaśnienie mojej „identycznej” instrukcji: Załaduj jedną zmienną za pomocą DateTime.Now, a drugą za pomocą DateTime.UtcNow, a następnie wydrukuj różnicę TimeSpan. Różnica wyniesie milisekundy, a nie godziny, zakładając, że dzieli Cię kilka godzin od GMT.
Carl Camera,
18

To dobre pytanie. Odświeżam go, aby dać trochę więcej szczegółów na temat .Net zachowuje się z różnymi Kindwartościami. Jak zauważa @Jan Zich, jest to naprawdę bardzo ważna właściwość i jest różnie ustawiany w zależności od tego, czy używasz, czy Nowteż UtcNow.

Wewnętrznie przechowywana jest data, w Ticksktórej (w przeciwieństwie do odpowiedzi @Carl Camera) różni się w zależności od tego, czy używasz Nowlub UtcNow.

DateTime.UtcNowzachowuje się jak inne języki. Ustawia Tickswartość GMT. Ustawia również Kindna Utc.

DateTime.Nowzmienia Tickswartość na taką, jaka byłaby, gdyby była to Twoja pora dnia w strefie czasowej GMT . Ustawia również Kindna Local.

Jeśli opóźnisz się o 6 godzin (GMT-6), otrzymasz czas GMT sprzed 6 godzin. .Net faktycznie ignoruje Kindi traktuje ten czas tak, jakby to było 6 godzin temu, nawet jeśli ma to być „teraz”. To się jeszcze bardziej psuje, jeśli utworzysz DateTimeinstancję, a następnie zmień strefę czasową i spróbuj z niej skorzystać.

Instancje DateTime z różnymi wartościami rodzaju nie są kompatybilne.

Spójrzmy na kod ...

    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

Jak widać tutaj, porównania i funkcje matematyczne nie są automatycznie konwertowane na zgodne czasy. TimespanPowinien być prawie jedna godzina, ale zamiast tego był prawie 6. „UTC <teraz” powinno być prawdziwe (nawet dodaje godzinę, aby mieć pewność), ale nadal była fałszywa.

Możesz także zobaczyć „obejście”, które polega na zamianie na czas uniwersalny w dowolnym miejscu, które Kindnie jest takie samo.

Moja bezpośrednia odpowiedź na pytanie zgadza się z zaleceniem przyjętej odpowiedzi, kiedy należy użyć każdego z nich. Zawsze powinieneś próbować pracować z DateTimeobiektami, które mają Kind=Utc, z wyjątkiem podczas operacji we / wy (wyświetlanie i parsowanie). Oznacza to, że prawie zawsze powinieneś używać DateTime.UtcNow, z wyjątkiem przypadków, w których tworzysz obiekt tylko po to, aby go wyświetlić i odrzucić go od razu.

Ted Bigham
źródło
7

DateTime nie ma pojęcia, jakie są strefy czasowe. Zawsze zakłada, że ​​jesteś w czasie lokalnym. UtcNow oznacza tylko „Odejmij moją strefę czasową od czasu”.

Jeśli chcesz używać dat uwzględniających strefę czasową, użyj DateTimeOffset , która reprezentuje datę / godzinę w strefie czasowej. Musiałem nauczyć się tego na własnej skórze.

Omer van Kloeten
źródło
9
Aby być całkowicie precyzyjnym (i unikać korzystania z Now przez UtcNow ze względów wydajnościowych), jest na odwrót: teraz dodaje strefę czasową do UtcNow i jest o wiele wolniejszy.
mafu
5

„Prosta” odpowiedź na pytanie brzmi:

DateTime.Now zwraca wartość DateTime reprezentującą bieżący czas systemowy (w dowolnej strefie czasowej, w której działa system). Właściwością DateTime.Kind będzie DateTimeKind.Local

DateTime.UtcNow zwraca wartość DateTime reprezentującą bieżący uniwersalny czas koordynowany (inaczej UTC), który będzie taki sam bez względu na strefę czasową systemu. Właściwością DateTime.Kind będzie DateTimeKind.Utc

PapillonUK
źródło
4

Mały dodatek do powyższych punktów: struktura DateTime zawiera także mało znane pole o nazwie Kind (przynajmniej nie wiedziałem o tym przez długi czas). Jest to w zasadzie tylko flaga wskazująca, czy czas jest lokalny, czy UTC; nie określa rzeczywistego przesunięcia względem UTC dla czasów lokalnych. Oprócz tego, że wskazuje, z jakimi intencjami zbudowano stuct, ma on również wpływ na sposób działania metod ToUniversalTime () i ToLocalTime () .

Jan Zich
źródło
1

DateTime.UtcNow jest ciągłą skalą czasową o pojedynczej wartości, natomiast DateTime.Now nie jest ciągłą ani pojedynczej wartości. Głównym powodem jest czas letni, który nie dotyczy UTC. Tak więc UTC nigdy nie przeskakuje o godzinę do przodu ani do tyłu, podczas gdy czas lokalny (DateTime.Now) tak. A kiedy przeskakuje do tyłu, ta sama wartość czasu występuje dwukrotnie.

użytkownik1315023
źródło
1

DateTime.UtcNow to uniwersalna skala czasu pomijająca czas letni. Tak więc UTC nigdy się nie zmienia z powodu DST.

Ale DateTime.Now nie jest ciągły ani pojedynczej wartości, ponieważ zmienia się zgodnie z DST. Co oznacza, że ​​DateTime.Now ta sama wartość czasu może wystąpić dwukrotnie, pozostawiając klientów w stanie zagubienia.

ChaiVan
źródło
0

Jeśli potrzebujesz czasu lokalnego na maszynę, na której działa Twoja aplikacja (np. CEST dla Europy), użyj Now. Jeśli chcesz czasu uniwersalnego - UtcNow. To tylko kwestia twoich preferencji - prawdopodobnie stworzenie lokalnej witryny / samodzielnej aplikacji, z której chciałbyś skorzystać, korzystając z czasu użytkownika - więc na to wpływa jego ustawienie strefy czasowej - DateTime.Now.

Pamiętaj tylko, że w przypadku strony internetowej jest to ustawienie strefy czasowej serwera. Więc jeśli wyświetlasz czas dla użytkownika, pobierz jego preferowaną strefę czasową i zmień czas (po prostu zapisz czas Utc w bazie danych i zmodyfikuj go) lub określ UTC. Jeśli zapomnisz to zrobić, użytkownik zobaczy coś w rodzaju: opublikował 3 minusy temu, a potem czas w przyszłości :)

kender
źródło
0

Duża różnica :) polega na tym, że DateTime.Now nie jest obsługiwany w przepływie pracy SharePoint, musisz użyć DateTime.UtcNow

Michel LAPLANE
źródło