Разница между 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функцию в Win32 API), а затем преобразуют значение в местный часовой пояс. (Поэтому DateTime.Now.ToUniversalTime()дороже чем DateTime.UtcNow.)

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

Итак, простой ответ - это DateTime.Todayэквивалент DateTime.Now.Date.
Но ИМХО - вы не должны использовать ни один из них, ни какие-либо из вышеперечисленных эквивалентов.

Когда вы запрашиваете 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?
Сэмюэл Лью
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: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;
  }
}
Guffa
источник
9

DateTime.Today представляет текущую системную дату с временной частью, установленной на 00:00:00.

и

DateTime.Now представляет текущую системную дату и время

daniel.herken
источник
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);
          }
        }
dekdev
источник
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
источник
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() будет отображать только дату

sunnyca99
источник