Різниця між System.DateTime.Now і System.DateTime.Today


127

Чи може хтось пояснити різницю між System.DateTime.Nowі System.DateTime.Todayв C # .NET? Плюси і мінуси кожного, якщо можливо.

Відповіді:


179

DateTime.Nowповертає DateTimeзначення, яке складається з локальної дати та часу комп'ютера, на якому працює код. Це DateTimeKind.Localпривласнив на своє Kindмайно. Це еквівалентно виклику будь-якого з наступного:

  • DateTime.UtcNow.ToLocalTime()
  • DateTimeOffset.UtcNow.LocalDateTime
  • DateTimeOffset.Now.LocalDateTime
  • TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local)
  • TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local)

DateTime.Todayповертає DateTimeзначення, яке має ті самі компоненти року, місяця та дня, як і будь-який із наведених вище виразів, але з часовими компонентами, встановленими на нуль. Це також є DateTimeKind.Localу своїй Kindвласності. Він еквівалентний будь-якому з наступного:

  • 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

Зауважте, що внутрішньо системний годинник має значення UTC, тому коли ви викликаєте DateTime.Nowйого спочатку отримує час UTC (через GetSystemTimeAsFileTimeфункцію в API Win32), а потім перетворює значення в локальний часовий пояс. (Тому DateTime.Now.ToUniversalTime()дорожче, ніж DateTime.UtcNow.)

Також зауважте, що він DateTimeOffset.Now.DateTimeбуде мати подібні значення DateTime.Now, але він матиме, DateTimeKind.Unspecifiedа не DateTimeKind.Local- що може призвести до інших помилок залежно від того, що ви робите з ним.

Отже, проста відповідь DateTime.Todayє рівнозначною DateTime.Now.Date.
Але IMHO - Ви не повинні використовувати ні один із цих, ні будь-який із зазначених вище еквівалентів.

Коли ви запитуєте DateTime.Now, ви запитуєте значення локального календарного годинника комп'ютера, на якому працює код. Але те, що ви отримаєте назад, не має жодної інформації про цей годинник! Найкраще, що ви отримуєте, це те DateTime.Now.Kind == DateTimeKind.Local. Але чия вона місцева? Ця інформація втрачається, як тільки ви щось зробите зі значенням, наприклад, зберігаєте її в базі даних, виводите її на екран або передаєте за допомогою веб-сервісу.

Якщо ваш місцевий часовий пояс дотримується будь-яких правил літнього часу, ви не отримаєте цю інформацію DateTime.Now. У неоднозначні часи, наприклад, під час переходу на "запасний", ви не знатимете, який з двох можливих моментів відповідає значенню, яке ви отримали DateTime.Now. Наприклад, скажіть, що встановлено часовий пояс вашої системи, Mountain Time (US & Canada)і ви запитаєте його DateTime.Nowв перші години 3 листопада 2013 року. Що означає результат 2013-11-03 01:00:00? Є два моменти миттєвого часу, представлені цим самим календарним датою. Якби я надіслав цю цінність комусь іншому, вони б не мали уявлення, про кого я маю на увазі. Особливо, якщо вони знаходяться в часовому поясі, де правила різні.

Найкраще, що ви могли б зробити, це використовувати DateTimeOffsetзамість цього:

// This will always be unambiguous.
DateTimeOffset now = DateTimeOffset.Now;

Тепер для того ж сценарію, який я описав вище, я отримую значення 2013-11-03 01:00:00 -0600перед переходом або 2013-11-03 01:00:00 -0700після переходу. Кожен, хто дивиться на ці значення, може сказати, що я мав на увазі.

Я написав допис у блозі на цю саму тему. Будь ласка, прочитайте - Справа проти DateTime.Now .

Також є деякі місця в цьому світі (наприклад, Бразилія), де перехід "весна вперед" відбувається саме опівночі. Годинники ходять з 23:59 до 01:00. Це означає, що значення, яке ви отримуєте DateTime.Todayна цю дату, не існує! Навіть якщо ви користуєтеся DateTimeOffset.Now.Date, ви отримуєте той же результат, і у вас все ще виникає ця проблема. Це тому, що традиційно такого Dateоб'єкта в .Net не було. Тож незалежно від того, як ви отримуєте цінність, як тільки ви позбавите часу - ви повинні пам’ятати, що воно насправді не означає «півночі», хоча це значення, з яким ви працюєте.

Якщо ви дійсно хочете повністю коректного вирішення цієї проблеми, найкращим підходом є використання NodaTime . LocalDateКлас правильно представляє собою дату без часу. Ви можете отримати поточну дату для будь-якого часового поясу, включаючи часовий пояс локальної системи:

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;

Якщо ви не хочете використовувати Noda Time, тепер є інший варіант. Я вніс внесок у проект .Net CoreFX Lab об'єкта, призначеного лише для дати . Ви можете знайти System.Timeоб'єкт пакета у їхньому каналі MyGet. Додавши до свого проекту, ви побачите, що можете зробити що-небудь із наступного:

using System;
...

Date localDate = Date.Today;

Date utcDate = Date.UtcToday;

Date tzSpecificDate = Date.TodayInTimeZone(anyTimeZoneInfoObject);

9
Що з використанням DateTime.UtcNowзамість DateTimeOffset.Now?
Samuel Liew

5
DateTime.UtcNowдопустимо, якщо ви можете передати у своїй програмі чи специфікації, що значення вказано в UTC. (Мені подобається насправді називати поле чи властивість чимось на кшталт, MyDateUtcа не просто MyDate- але це просто обмерзання на торті.) Якщо ви не можете передати це у специфікації чи імені поля, то DateTimeOffset.UtcNowможна використовувати для забезпечення нульового зміщення зі значеннями дати та часу.
Метт Джонсон-Пінт

Вони не рівні. Сьогодні є час, як 00:00:00.
Джеймс Вілкінс

@JamesWilkins - Не впевнений, що ти отримуєш. Так і робить DateTime.Now.Date.
Метт Джонсон-Пінт

@MattJohnson Питання задає різницю між DateTime.Today і DateTime.Now, а не DateTime.Today і DateTime.Now.Date.
Девід Андерсон

85

Час. .Nowвключає 09:23:12 чи що завгодно; .Todayє лише частиною дати (о 00:00 у цей день).

Тому використовуйте, .Nowякщо ви хочете включити час і .Todayякщо ви просто хочете побачити!

.Today по суті те саме, що .Now.Date


27
... і використовувати, UtcNowякщо ви дійсно не хочете, щоб системний локальний часовий пояс. (Зокрема, у веб-додатку, який майже завжди є неправильним вибором.)
Джон Скіт

22

DateTime.NowВластивість повертає поточну дату і час, наприклад 2011-07-01 10:09.45310.

DateTime.TodayВластивість повертає поточну дату з часом compnents , встановленим в нуль, наприклад 2011-07-01 00:00.00000.

DateTime.TodayВластивість фактично реалізується для повернення DateTime.Now.Date:

public static DateTime Today {
  get {
    DateTime now = DateTime.Now;
    return now.Date;
  }
}

9

DateTime.Today представляє поточну дату системи з часовою частиною, встановленою на 00:00:00

і

DateTime.Now представляє поточну дату та час системи


2
просто спостереження ... документація 1.1 набагато менш деталізована, ніж 4.0 документація; можливо, краще посилання на vLatest?
Марк Гравелл

3
@megaperlz: Ви зараз посилаєтесь на 4.0, а не vLatest. Посилання VLatest можна зробити, видаливши (v=VS.100).
Брайан

6

Я думав додати ці посилання -

Повертаючись до початкового питання, за допомогою Reflector я пояснив різницю в коді

 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);
          }
        }

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

1

DateTime.Todayце DateTime.Nowз часом , встановленим на нуль.

Важливо зазначити, що існує різниця між значенням DateTime, що представляє кількість тиків, що минули з півночі 1 січня 0000 року, і рядковим поданням цього значення DateTime, яке виражає значення дати та часу в специфічний для культури формат: https://msdn.microsoft.com/en-us/library/system.datetime.now%28v=vs.110%29.aspx

DateTime.Now.Ticks- це фактичний час, що зберігається .net (фактично час UTC), решта - лише представлення (важливі для цілей відображення).

Якщо Kindвластивість є, DateTimeKind.Localвона неявно включає інформацію про часовий пояс на локальному комп'ютері. При надсиланні через веб-службу .net, значення DateTime за замовчуванням серіалізуються з включеною інформацією про часовий пояс, наприклад, 2008-10-31T15: 07: 38.6875000-05: 00, а комп'ютер в іншому часовому поясі все ще може точно знати, який час на які посилаються.

Отже, з використанням DateTime.Now і DateTime.Today цілком нормально.

Зазвичай у вас виникають проблеми, коли ви починаєте плутати представлення рядків з фактичним значенням і намагаєтесь "виправити" DateTime, коли воно не порушено.


-1

DateTime.Now.ToShortDateString() відображатиметься лише частина дати

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.