Różnica między System.DateTime.Now i System.DateTime.Today

127

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.

Samuel Liew
źródło

Odpowiedzi:

179

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.LocalDateTime
  • DateTimeOffset.Now.LocalDateTime
  • TimeZoneInfo.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.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.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);
Matt Johnson-Pint
źródło
9
A co z użyciem DateTime.UtcNowzamiast DateTimeOffset.Now?
Samuel Liew
5
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.
Matt Johnson-Pint
Nie są równi. Dzisiaj jest godzina 00:00:00.
James Wilkins,
@JamesWilkins - Nie jestem pewien, do czego zmierzasz. Tak też DateTime.Now.Date.
Matt Johnson-Pint
@MattJohnson Pytanie dotyczy różnicy między DateTime.Today i DateTime.Now, a nie DateTime.Today i DateTime.Now.Date.
David Anderson,
85

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

Marc Gravell
źródło
27
... i używaj, UtcNowchyba że naprawdę chcesz ustawić lokalną strefę czasową systemu. (W szczególności w aplikacji internetowej, która prawie zawsze jest złym wyborem).
Jon Skeet,
22

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;
  }
}
Guffa
źródło
9

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ą

daniel.herken
źródło
2
tylko obserwacja ... dokumentacja 1.1 jest znacznie mniej szczegółowa niż dokumentacja 4.0; może lepiej jest połączyć się z vLatest?
Marc Gravell
3
@megaperlz: Teraz łączysz się z wersją 4.0 zamiast vLatest. Łącza VLatest można utworzyć, usuwając plik (v=VS.100).
Brian
6

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);
          }
        }
dekdev
źródło
5
DateTime dt = new DateTime();// gives 01/01/0001 12:00:00 AM
DateTime dt = DateTime.Now;// gives today date with current time
DateTime dt = DateTime.Today;// gives today date and 12:00:00 AM time
deepi
źródło
1

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.

Kobus
źródło
-1

DateTime.Now.ToShortDateString() wyświetli tylko część daty

sunnyca99
źródło