Ответ 1
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
, которое имеет те же компоненты year, month и day как любое из приведенных выше выражений, но с компонентами времени, установленными на ноль. Он также имеет 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
? Есть два момента мгновенного времени, представленных этим самым календарем datetime. Если бы я послал это значение кому-то другому, они бы понятия не имели, что я имел в виду. Особенно, если они находятся в часовом поясе, где правила разные.
Лучшее, что вы могли бы сделать, это использовать вместо 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.
Кроме того, в этом мире есть места (например, Бразилия), где переход "spring -forward" происходит точно в полночь. Часы идут с 23:59 до 01:00. Это означает, что значение, которое вы получаете за DateTime.Today
в эту дату, не существует! Даже если вы используете DateTimeOffset.Now.Date
, вы получаете тот же результат, и у вас все еще есть эта проблема. Это потому, что традиционно в .NET не было объекта 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, теперь есть еще один вариант. Я внедрил реализацию объекта только для даты в проект