DateTime.Now vs. DateTime.UtcNow


225

Мені було цікаво, які саме принципи роботи двох властивостей. Я знаю, що другий є універсальним і в основному не стосується часових поясів, але чи може хтось детально пояснити, як вони працюють і який слід використовувати в якому сценарії?


1
можливо, буде занадто пізно, але я хочу вказати на цей блог: blog.angeloflogic.com/2013/10/…
Kai Wang

невелика лава для розмітки rextester.com/QRDR82396
Даніель Б

Відповіді:


346

DateTime.UtcNow повідомляє вам дату та час, як це було б у універсальний координований час, який також називають часовим поясом середнього часового режиму Грінвіч - в основному, як це було б, якби ви були в Лондонській Англії, але не влітку. DateTime.Now вказує дату та час, як вони відображатимуться для когось у вашому поточному регіоні.

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


84
відмінний момент - коли ви зберігаєте дати в базі даних або файлі, обов'язково зберігайте їх у UTC!
Джефф Етвуд

15
Ви повинні зауважити, що коли ви хочете зберігати дати в UTC у базі даних, ви повинні переконатися, що база даних не додає власний часовий пояс до дат, які не дають явних часових поясів. Зауважте, що DateTime завжди буде використовувати поточний часовий пояс, коли його запитують.
Омер ван Клотен

@OmervanKloeten дає дуже хороший момент. Мені цікаво, чи є для цього елегантне «всебічне» рішення, щоб кожен раз правильно зберігати та отримувати дати, навіть якщо ваш IIS та SQL сервер знаходяться в різних часових поясах.
TheGeekZn

1
@ JoshYates1980 Так, ви просто робите DateTime.UtcNow.AddYears (1)
CathalMF

3
Використовуйте NodaTime - це змусить задуматися про час більш корисним способом і
уникне

86

Це дійсно досить просто, тому я думаю, це залежить від того, яка ваша аудиторія та де вони живуть.

Якщо ви не використовуєте Utc, ви повинні знати часовий пояс людини, якій ви показуєте дати та час, інакше ви скажете їм, що сталося о 15:00 у системний або серверний час, коли це дійсно сталося о 17:00, де вони трапляються жити.

Ми використовуємо це DateTime.UtcNowтому, що у нас є глобальна аудиторія в Інтернеті, і тому, що я не вважаю за потрібне кожним користувачем заповнювати форму із зазначенням того, в якому часовому поясі вони живуть.

Ми також відображаємо відносний час (2 години тому, 1 день тому і т. Д.), Поки публікація не стане достатньою, щоб час був "тим самим", незалежно від того, де ви живете на Землі.


Я також хочу по-друге, що зберігання DateTime.UtcNow також потрібне лише тоді, коли зроблено розрахунок з двома датами, щоб отримати правильні години. Коли мені просто потрібно відобразити DateAt Date, то Datetime.Now достатньо.
Елізабет

36

Також врахуйте різницю у виконанні; DateTime.UtcNowце десь у 30 разів швидше DateTime.Now, тому що внутрішньо DateTime.Nowробиться багато коригувань часового поясу (ви можете легко перевірити це за допомогою Reflector).

Тому НЕ використовуйте DateTime.Nowдля відносних вимірювань часу.


Це сприйняло мені болісну подорож, просто знаю, що UtcNow має кращі показники, а просто збереження ваших дат у mysql та припускаючи, що це унтер та порівняння дисплеїв, залежних від дати, з UtcNow спрощує цю глобальну проблему часового поясу
Diin

29

Одна з основних для розуміння концепція в .NET є те , що в даний час не є в даний час по всій землі незалежно від того , в якому часовому поясі ви знаходитесь в так що якщо ви завантажте змінну с. DateTime.NowАбо DateTime.UtcNow-. Призначення ідентично * Ваш DateTimeоб'єкт знає , що часовий пояс , ви перебуваєте в і враховує це незалежно від призначення.

Корисність DateTime.UtcNowкорисна для підрахунку дат через межі літнього часу. Тобто в місцях, які беруть участь у переході на літній час, інколи буває 25 годин з полудня до полудня наступного дня, а іноді - 23 години між полуднем та полуднем наступного дня. Якщо ви хочете правильно визначити кількість годин з часу А та часу В, вам потрібно спочатку перевести кожну їхню еквівалентну UTC, перш ніж обчислити значення TimeSpan.

Про це висвітлюється повідомлення в блозі, який я писав, що далі пояснює TimeSpan, і включає посилання на ще більш обширну статтю MS на цю тему.

* Пояснення: будь-яке завдання буде зберігати поточний час. Якщо ви повинні були завантажити дві змінних один через , DateTime.Now()а інші з допомогою DateTime.UtcNow()до TimeSpanрізниці між ними будуть мілісекунди, а не годинник , які передбачають ви перебуваєте в часовому поясі годин їзди від GMT. Як зазначалося нижче, при виведенні їх Stringзначень відображатимуться різні рядки.


1
Щодо "завантаження змінної за допомогою DateTime.Now або DateTime.UtcNow - призначення ідентичне": Це, можливо, потрібно буде уточнити? Коли я сиджу тут, у часовому поясі EDT (UTC -4), я призначив дві змінні DateTime.UtcNow та DateTime.Now відповідно, а потім надрукував їх значення за допомогою ToString (). Відображені значення були 4 години один від одного - не "однакові".
Джон Шнайдер

2
@JonSchneider, я вважаю, ти прав. Заява: "присвоєння однакове" не відповідає дійсності. ToString (), мабуть, не найкращий спосіб перевірити це, оскільки він може відображати рівні дати по-різному (як це робить Java). Функції порівняння є кращим тестом, і вони показують, що вони дійсно не рівні.
Тед Бігхем

Пояснення до мого "ідентичного" твердження: Завантажте одну змінну через DateTime.Now та іншу за допомогою DateTime.UtcNow, а потім надрукуйте різницю TimeSpan. Різниця становитиме мілісекунди, а не години, якщо припустити, що ви за годиною від ГМТ.
Камера Карла

18

Це гарне запитання. Я відроджую це, щоб трохи детальніше розповісти про те, як .Net поводиться з різними Kindзначеннями. Як зазначає @Jan Zich, це насправді критично важлива властивість і встановлюється по-різному залежно від того, використовуєте ви Nowчи UtcNow.

Внутрішня дата зберігається так, Ticksщо (всупереч відповіді @Carl Camera) відрізняється залежно від того, використовуєте ви Nowчи UtcNow.

DateTime.UtcNowповодиться як інші мови. Він встановлює Ticksзначення на основі GMT. Він також налаштований Kindна Utc.

DateTime.Nowзмінює Ticksзначення на те, яке воно було б, якби ваш час доби знаходився у часовому поясі GMT . Він також налаштований Kindна Local.

Якщо ви відстали на 6 годин (GMT-6), ви отримаєте час GMT з 6 годин тому. .Net насправді ігнорує Kindта ставиться до цього часу так, ніби це було 6 годин тому, навіть якщо це повинно бути "зараз". Це збільшується ще більше, якщо ви створюєте DateTimeекземпляр, а потім змініть свій часовий пояс і спробуйте його використовувати.

Екземпляри DateTime з різними значеннями 'Kind' НЕ сумісні.

Давайте подивимось на якийсь код ...

    DateTime utc = DateTime.UtcNow;
    DateTime now = DateTime.Now;
    Debug.Log (utc + " " + utc.Kind);  // 05/20/2015 17:19:27 Utc
    Debug.Log (now + " " + now.Kind);  // 05/20/2015 10:19:27 Local

    Debug.Log (utc.Ticks);  // 635677391678617830
    Debug.Log (now.Ticks);  // 635677139678617840

    now = now.AddHours(1);
    TimeSpan diff = utc - now;
    Debug.Log (diff);  // 05:59:59.9999990

    Debug.Log (utc <  now);  // false
    Debug.Log (utc == now);  // false
    Debug.Log (utc >  now);  // true

    Debug.Log (utc.ToUniversalTime() <  now.ToUniversalTime());  // true
    Debug.Log (utc.ToUniversalTime() == now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() >  now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() -  now.ToUniversalTime());  // -01:00:00.0000010

Як ви бачите тут, порівняння та математичні функції не автоматично перетворюються на сумісні часи. TimespanМав майже одну годину, але замість цього був майже 6. «UTC <зараз» має бути правдою (я навіть додав годину , щоб переконатися), але по - , як і раніше помилково.

Ви також можете побачити "роботу навколо", яка полягає в тому, щоб просто перетворити на універсальний час в будь-якому місці, яке Kindне є однаковим.

Моя пряма відповідь на питання узгоджується з рекомендацією прийнятої відповіді про те, коли використовувати кожну. Ви завжди повинні намагатися працювати з DateTimeоб'єктами, які є Kind=Utc, за винятком під час вводу-виводу (відображення та розбір). Це означає, що ви майже завжди повинні користуватися DateTime.UtcNow, за винятком випадків, коли ви створюєте об’єкт просто для його відображення та відкидаєте його відразу.


7

DateTime поняття не має, що таке часові пояси. Це завжди передбачає, що ви знаходитесь у свій місцевий час. UtcNow означає лише "Відняти мій часовий пояс із часу".

Якщо ви хочете використовувати дати, відомі часовому поясу, використовуйте DateTimeOffset , який представляє дату / час із часовим поясом. Мені довелося навчитися тому важкому шляху.


9
Щоб бути абсолютно точним (і уникати використання користувачем Now over UtcNow з міркувань продуктивності), це навпаки: тепер додає часовий пояс до UtcNow і насправді на повільність.
мафу

5

"Проста" відповідь на питання:

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

DateTime.UtcNow повертає значення DateTime, що представляє поточний універсальний координований час (також UTC), яке буде однаковим, незалежно від часового поясу системи. DateTime.Kind майно буде DateTimeKind.Utc


4

Лише невелике доповнення до наведених вище пунктів: структура DateTime також містить маловідоме поле під назвою Kind (принаймні, я про це давно не знав). Це в основному лише прапор, який вказує, чи місцевий час або UTC; він не визначає реального зміщення від UTC за місцевим часом. Крім того, що вказує на те, з якими намірами була побудована стука, це також впливає на те, як працюють методи ToUniversalTime () та ToLocalTime () .


3

1

DateTime.UtcNow - це безперервна однозначна часова шкала, тоді як DateTime.Now не є безперервною або однозначною. Основна причина - літній час, який не застосовується до UTC. Тож UTC ніколи не стрибає вперед або назад години, тоді як місцевий час (DateTime.Now). І коли вона стрибає назад, однакове значення часу виникає двічі.


1

DateTime.UtcNow - це універсальна шкала часу, опускаючи літній час. Тож UTC ніколи не змінюється через DST.

Але, DateTime.Now не є безперервним або однозначним, оскільки він змінюється відповідно до DST. Що означає DateTime.Now, однакове значення часу може виникати двічі, залишаючи клієнтів у заплутаному стані.


0

Коли вам потрібен місцевий час для роботи машини, на якій працює ваша програма (наприклад, CEST для Європи), використовуйте Асистент. Якщо ви хочете універсальний час - UtcNow. Це лише питання ваших уподобань - можливо, зробивши локальний веб-сайт / окрему програму, яку ви хочете використовувати час, який має користувач - так це впливає його налаштування часового поясу - DateTime.Now.

Пам'ятайте лише, що для веб-сайту це налаштування часового поясу сервера. Отже, якщо ви показуєте користувачеві час, або отримайте його бажаний часовий пояс і змістіть час (просто збережіть час Utc у базі даних та змініть його) або вкажіть, що це UTC. Якщо ви забудете це зробити, користувач може побачити щось на зразок: опубліковано 3 мінуси тому, а потім поруч із ним час у майбутньому :)


0

Велика різниця :) полягає в тому, що DateTime.Now не підтримується в SharePoint Workflow, ви повинні використовувати DateTime.UtcNow

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