Чи може хтось пояснити різницю між System.DateTime.Nowі System.DateTime.Todayв C # .NET? Плюси і мінуси кожного, якщо можливо.
Чи може хтось пояснити різницю між System.DateTime.Nowі System.DateTime.Todayв C # .NET? Плюси і мінуси кожного, якщо можливо.
Відповіді:
DateTime.Nowповертає DateTimeзначення, яке складається з локальної дати та часу комп'ютера, на якому працює код. Це DateTimeKind.Localпривласнив на своє Kindмайно. Це еквівалентно виклику будь-якого з наступного:
DateTime.UtcNow.ToLocalTime()DateTimeOffset.UtcNow.LocalDateTimeDateTimeOffset.Now.LocalDateTimeTimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local)TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local)DateTime.Todayповертає DateTimeзначення, яке має ті самі компоненти року, місяця та дня, як і будь-який із наведених вище виразів, але з часовими компонентами, встановленими на нуль. Це також є DateTimeKind.Localу своїй Kindвласності. Він еквівалентний будь-якому з наступного:
DateTime.Now.DateDateTime.UtcNow.ToLocalTime().DateDateTimeOffset.UtcNow.LocalDateTime.DateDateTimeOffset.Now.LocalDateTime.DateTimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local).DateTimeZoneInfo.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);
DateTime.UtcNowдопустимо, якщо ви можете передати у своїй програмі чи специфікації, що значення вказано в UTC. (Мені подобається насправді називати поле чи властивість чимось на кшталт, MyDateUtcа не просто MyDate- але це просто обмерзання на торті.) Якщо ви не можете передати це у специфікації чи імені поля, то DateTimeOffset.UtcNowможна використовувати для забезпечення нульового зміщення зі значеннями дати та часу.
DateTime.Now.Date.
Час. .Nowвключає 09:23:12 чи що завгодно; .Todayє лише частиною дати (о 00:00 у цей день).
Тому використовуйте, .Nowякщо ви хочете включити час і .Todayякщо ви просто хочете побачити!
.Today по суті те саме, що .Now.Date
UtcNowякщо ви дійсно не хочете, щоб системний локальний часовий пояс. (Зокрема, у веб-додатку, який майже завжди є неправильним вибором.)
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;
}
}
DateTime.Today представляє поточну дату системи з часовою частиною, встановленою на 00:00:00
і
DateTime.Now представляє поточну дату та час системи
(v=VS.100).
Я думав додати ці посилання -
Повертаючись до початкового питання, за допомогою 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);
}
}
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, коли воно не порушено.
DateTime.UtcNowзамістьDateTimeOffset.Now?