Czy ktoś może wyjaśnić różnicę między System.DateTime.Now
iw System.DateTime.Today
C # .NET? Plusy i minusy każdego, jeśli to możliwe.
Czy ktoś może wyjaśnić różnicę między System.DateTime.Now
iw System.DateTime.Today
C # .NET? Plusy i minusy każdego, jeśli to możliwe.
Odpowiedzi:
DateTime.Now
zwraca DateTime
wartość składającą się z lokalnej daty i godziny komputera, na którym działa kod. Ma DateTimeKind.Local
przypisany do swojej Kind
własności. Jest to równoważne wywołaniu dowolnego z poniższych:
DateTime.UtcNow.ToLocalTime()
DateTimeOffset.UtcNow.LocalDateTime
DateTimeOffset.Now.LocalDateTime
TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local)
TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local)
DateTime.Today
zwraca DateTime
wartość, która ma te same składniki roku, miesiąca i dnia, co każde z powyższych wyrażeń, ale ze składnikami czasu ustawionymi na zero. Ma również DateTimeKind.Local
w swoim Kind
majątku. Odpowiada dowolnemu z poniższych:
DateTime.Now.Date
DateTime.UtcNow.ToLocalTime().Date
DateTimeOffset.UtcNow.LocalDateTime.Date
DateTimeOffset.Now.LocalDateTime.Date
TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local).Date
TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local).Date
Zauważ, że wewnętrznie zegar systemowy jest podany w czasie UTC, więc kiedy DateTime.Now
go wywołasz , najpierw pobiera czas UTC (za pomocą GetSystemTimeAsFileTime
funkcji w Win32 API), a następnie konwertuje wartość na lokalną strefę czasową. (Dlatego DateTime.Now.ToUniversalTime()
jest droższy niż DateTime.UtcNow
.)
Zauważ również, że DateTimeOffset.Now.DateTime
będzie miał podobne wartości do DateTime.Now
, ale będzie miał DateTimeKind.Unspecified
raczej niż DateTimeKind.Local
- co może prowadzić do innych błędów w zależności od tego, co z nim zrobisz.
Tak więc prosta odpowiedź jest taka sama, DateTime.Today
jak DateTime.Now.Date
.
Ale IMHO - Nie powinieneś używać żadnego z tych ani żadnego z powyższych odpowiedników.
Kiedy pytasz DateTime.Now
, pytasz o wartość lokalnego zegara kalendarzowego komputera, na którym działa kod. Ale to, co otrzymujesz, nie zawiera żadnych informacji o tym zegarze! Najlepsze, co dostajesz, to to DateTime.Now.Kind == DateTimeKind.Local
. Ale czyja to lokalizacja? Informacje te zostaną utracone, gdy tylko wykonasz cokolwiek z wartością, na przykład przechowujesz ją w bazie danych, wyświetlasz na ekranie lub przesyłasz za pomocą usługi internetowej.
Jeśli lokalna strefa czasowa jest zgodna z jakimikolwiek zasadami dotyczącymi czasu letniego, nie otrzymasz tych informacji z powrotem DateTime.Now
. W niejednoznacznych momentach, na przykład podczas przejścia „rezerwowego”, nie będziesz wiedział, który z dwóch możliwych momentów odpowiada wartości, z którą pobrałeś DateTime.Now
. Na przykład, powiedzmy, że strefa czasowa Twojego systemu jest ustawiona na Mountain Time (US & Canada)
i pytasz o nią DateTime.Now
we wczesnych godzinach rannych 3 listopada 2013 r. Co oznacza wynik 2013-11-03 01:00:00
? Istnieją dwa momenty chwilowego czasu reprezentowane przez tę samą kalendarzową datę i godzinę. Gdybym miał wysłać tę wartość komuś innemu, nie mieliby pojęcia, o którą mi chodzi. Zwłaszcza jeśli znajdują się w strefie czasowej, w której zasady są inne.
Najlepszą rzeczą, jaką możesz zrobić, byłoby użycie DateTimeOffset
zamiast tego:
// This will always be unambiguous.
DateTimeOffset now = DateTimeOffset.Now;
Teraz dla tego samego scenariusza, który opisałem powyżej, otrzymuję wartość 2013-11-03 01:00:00 -0600
przed przejściem lub 2013-11-03 01:00:00 -0700
po przejściu. Każdy, kto spojrzy na te wartości, może powiedzieć, o co mi chodzi.
Napisałem wpis na blogu właśnie na ten temat. Przeczytaj - Sprawa przeciwko DateTime.Now .
Są też miejsca na tym świecie (np. Brazylia), w których „wiosenno-naprzód” następuje dokładnie o północy. Zegary idą od 23:59 do 01:00. Oznacza to, że wartość, którą otrzymujesz DateTime.Today
w tym dniu, nie istnieje! Nawet jeśli używasz DateTimeOffset.Now.Date
, uzyskujesz ten sam wynik i nadal masz ten problem. Dzieje się tak, ponieważ tradycyjnie Date
w .Net nie było czegoś takiego jak obiekt. Więc niezależnie od tego, w jaki sposób uzyskasz wartość, kiedy pozbędziesz się czasu - musisz pamiętać, że tak naprawdę nie reprezentuje on „północy”, nawet jeśli jest to wartość, z którą pracujesz.
Jeśli naprawdę chcesz w pełni poprawnego rozwiązania tego problemu, najlepszym rozwiązaniem jest użycie NodaTime . LocalDate
Klasa właściwie reprezentuje datę bez czasu. Możesz uzyskać aktualną datę dla dowolnej strefy czasowej, w tym lokalnej strefy czasowej systemu:
using NodaTime;
...
Instant now = SystemClock.Instance.Now;
DateTimeZone zone1 = DateTimeZoneProviders.Tzdb.GetSystemDefault();
LocalDate todayInTheSystemZone = now.InZone(zone1).Date;
DateTimeZone zone2 = DateTimeZoneProviders.Tzdb["America/New_York"];
LocalDate todayInTheOtherZone = now.InZone(zone2).Date;
Jeśli nie chcesz używać czasu Noda, jest teraz inna opcja. Wniosłem wkład w implementację obiektu zawierającego tylko datę do projektu .Net CoreFX Lab . Możesz znaleźć System.Time
obiekt pakietu w ich kanale MyGet. Po dodaniu do projektu zobaczysz, że możesz wykonać jedną z następujących czynności:
using System;
...
Date localDate = Date.Today;
Date utcDate = Date.UtcToday;
Date tzSpecificDate = Date.TodayInTimeZone(anyTimeZoneInfoObject);
DateTime.UtcNow
jest do zaakceptowania, jeśli możesz przekazać w swojej aplikacji lub specyfikacji, że wartość jest w czasie UTC. (W rzeczywistości lubię nazywać pole lub właściwość czymś w rodzaju, MyDateUtc
a nie tylko MyDate
- ale to tylko wisienka na torcie). Jeśli nie możesz tego przekazać w specyfikacji lub nazwie pola, DateTimeOffset.UtcNow
można użyć do zapewnienia, że przesunięcie zerowe zostanie przekazane z wartościami daty i godziny.
DateTime.Now.Date
.
Czas. .Now
obejmuje 09:23:12 lub cokolwiek; .Today
jest tylko częścią daty (o 00:00:00 tego dnia).
Użyj więc, .Now
jeśli chcesz uwzględnić godzinę i .Today
tylko datę!
.Today
jest zasadniczo taki sam jak .Now.Date
UtcNow
chyba że naprawdę chcesz ustawić lokalną strefę czasową systemu. (W szczególności w aplikacji internetowej, która prawie zawsze jest złym wyborem).
DateTime.Now
Właściwość zwraca bieżącą datę i czas, na przykład 2011-07-01 10:09.45310
.
DateTime.Today
Właściwość zwraca bieżącą datę z compnents czas ustawiony na zero, na przykład 2011-07-01 00:00.00000
.
DateTime.Today
Nieruchomość faktycznie realizowana jest do zwrotu DateTime.Now.Date
:
public static DateTime Today {
get {
DateTime now = DateTime.Now;
return now.Date;
}
}
DateTime.Today reprezentuje bieżącą datę systemową z częścią czasową ustawioną na 00:00:00
i
DateTime.Now reprezentuje bieżącą datę i godzinę systemową
(v=VS.100)
.
Myślałem o dodaniu tych linków -
Wracając do pierwotnego pytania, używając Reflectora wyjaśniłem różnicę w kodzie
public static DateTime Today
{
get
{
return DateTime.Now.Date; // It returns the date part of Now
//Date Property
// returns same date as this instance, and the time value set to 12:00:00 midnight (00:00:00)
}
}
private const long TicksPerMillisecond = 10000L;
private const long TicksPerDay = 864000000000L;
private const int MillisPerDay = 86400000;
public DateTime Date
{
get
{
long internalTicks = this.InternalTicks; // Date this instance is converted to Ticks
return new DateTime((ulong) (internalTicks - internalTicks % 864000000000L) | this.InternalKind);
// Modulo of TicksPerDay is subtracted - which brings the time to Midnight time
}
}
public static DateTime Now
{
get
{
/* this is why I guess Jon Skeet is recommending to use UtcNow as you can see in one of the above comment*/
DateTime utcNow = DateTime.UtcNow;
/* After this i guess it is Timezone conversion */
bool isAmbiguousLocalDst = false;
long ticks1 = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utcNow, out isAmbiguousLocalDst).Ticks;
long ticks2 = utcNow.Ticks + ticks1;
if (ticks2 > 3155378975999999999L)
return new DateTime(3155378975999999999L, DateTimeKind.Local);
if (ticks2 < 0L)
return new DateTime(0L, DateTimeKind.Local);
else
return new DateTime(ticks2, DateTimeKind.Local, isAmbiguousLocalDst);
}
}
DateTime.Today
ma DateTime.Now
czas ustawiony na zero.
Należy zauważyć, że istnieje różnica między wartością DateTime, która reprezentuje liczbę taktów, które upłynęły od północy 1 stycznia 0000 r., A ciągiem reprezentującym tę wartość DateTime, która wyraża wartość daty i godziny w format specyficzny dla kultury: https://msdn.microsoft.com/en-us/library/system.datetime.now%28v=vs.110%29.aspx
DateTime.Now.Ticks
to rzeczywisty czas przechowywany przez .net (zasadniczo czas UTC), reszta to tylko reprezentacje (które są ważne do celów wyświetlania).
Jeśli Kind
właściwość ma wartość DateTimeKind.Local
, zawiera ona niejawnie informacje o strefie czasowej komputera lokalnego. Podczas wysyłania przez usługę internetową .net wartości DateTime są domyślnie serializowane z dołączonymi informacjami o strefie czasowej, np. 2008-10-31T15: 07: 38.6875000-05: 00, a komputer w innej strefie czasowej może nadal dokładnie wiedzieć, która godzina jest o którym mowa.
Tak więc używanie DateTime.Now i DateTime.Today jest całkowicie OK.
Zwykle wpadasz w kłopoty, gdy zaczynasz mylić reprezentację łańcuchową z rzeczywistą wartością i próbujesz „naprawić” DateTime, kiedy nie jest uszkodzony.
DateTime.UtcNow
zamiastDateTimeOffset.Now
?