Czy ktoś może wyjaśnić różnicę między System.DateTime.Nowiw System.DateTime.TodayC # .NET? Plusy i minusy każdego, jeśli to możliwe.
Czy ktoś może wyjaśnić różnicę między System.DateTime.Nowiw System.DateTime.TodayC # .NET? Plusy i minusy każdego, jeśli to możliwe.
Odpowiedzi:
DateTime.Nowzwraca DateTimewartość składającą się z lokalnej daty i godziny komputera, na którym działa kod. Ma DateTimeKind.Localprzypisany do swojej Kindwłasności. Jest to równoważne wywołaniu dowolnego z poniższych:
DateTime.UtcNow.ToLocalTime()DateTimeOffset.UtcNow.LocalDateTimeDateTimeOffset.Now.LocalDateTimeTimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local)TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local)DateTime.Todayzwraca DateTimewartość, 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.Localw swoim Kindmajątku. Odpowiada dowolnemu z poniższych:
DateTime.Now.DateDateTime.UtcNow.ToLocalTime().DateDateTimeOffset.UtcNow.LocalDateTime.DateDateTimeOffset.Now.LocalDateTime.DateTimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local).DateTimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local).DateZauważ, że wewnętrznie zegar systemowy jest podany w czasie UTC, więc kiedy DateTime.Nowgo wywołasz , najpierw pobiera czas UTC (za pomocą GetSystemTimeAsFileTimefunkcji 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.DateTimebędzie miał podobne wartości do DateTime.Now, ale będzie miał DateTimeKind.Unspecifiedraczej 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.Todayjak 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.Nowwe 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 DateTimeOffsetzamiast 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 -0600przed przejściem lub 2013-11-03 01:00:00 -0700po 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.Todayw 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 Datew .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 . LocalDateKlasa 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.Timeobiekt 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.UtcNowjest 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, MyDateUtca nie tylko MyDate- ale to tylko wisienka na torcie). Jeśli nie możesz tego przekazać w specyfikacji lub nazwie pola, DateTimeOffset.UtcNowmożna użyć do zapewnienia, że przesunięcie zerowe zostanie przekazane z wartościami daty i godziny.
DateTime.Now.Date.
Czas. .Nowobejmuje 09:23:12 lub cokolwiek; .Todayjest tylko częścią daty (o 00:00:00 tego dnia).
Użyj więc, .Nowjeśli chcesz uwzględnić godzinę i .Todaytylko datę!
.Today jest zasadniczo taki sam jak .Now.Date
UtcNowchyba że naprawdę chcesz ustawić lokalną strefę czasową systemu. (W szczególności w aplikacji internetowej, która prawie zawsze jest złym wyborem).
DateTime.NowWłaściwość zwraca bieżącą datę i czas, na przykład 2011-07-01 10:09.45310.
DateTime.TodayWłaściwość zwraca bieżącą datę z compnents czas ustawiony na zero, na przykład 2011-07-01 00:00.00000.
DateTime.TodayNieruchomość 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.Todayma DateTime.Nowczas 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.Ticksto rzeczywisty czas przechowywany przez .net (zasadniczo czas UTC), reszta to tylko reprezentacje (które są ważne do celów wyświetlania).
Jeśli Kindwł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.UtcNowzamiastDateTimeOffset.Now?