it-swarm-ru.tech

DateTime.Now против DateTime.UtcNow

Мне было интересно, каковы принципы работы этих двух свойств. Я знаю, что второй является универсальным и в основном не имеет дело с часовыми поясами, но может ли кто-нибудь подробно объяснить, как они работают и какой из них следует использовать в каком сценарии?

192
Slavo

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

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

306
Blair Conrad

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

Если вы не используете Utc, вы должны знать часовой пояс человека, которому вы показываете дату и время - в противном случае вы скажете им, что что-то произошло в 3 PM в системное или серверное время, когда это действительно произошло в 5 PM, где они живут.

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

Мы также отображаем относительное время (2 часа назад, 1 день назад и т.д.) До тех пор, пока сообщение не станет достаточно старым, чтобы время было "одинаковым" независимо от того, где на Земле вы живете.

80
Jeff Atwood

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

Поэтому не используйте DateTime.Now для измерения относительного времени.

29
Magnus Krisell

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

Полезность DateTime.UtcNow оказывается полезной при расчете дат за пределами летнего времени. То есть в местах, которые участвуют в переходе на летнее время, иногда с полудня до полудня следующего дня бывает 25 часов, а иногда между полуднем и полднем следующего дня 23 часа. Если вы хотите правильно определить количество часов от времени A и времени B, вам необходимо сначала перевести каждый из них в их UTC-эквиваленты, прежде чем вычислять TimeSpan.

Это покрыто сообщение в блоге, которое я написал , которое далее объясняет TimeSpan, и включает ссылку на еще более обширную статью MS по этой теме.

* Уточнение: любое назначение будет хранить текущее время. Если вам нужно было загрузить две переменные, одну из которых через DateTime.Now(), а другую через DateTime.UtcNow(), разница TimeSpan между ними составит миллисекунды, а не часы, если вы находитесь в часовом поясе в часах от GMT. Как отмечено ниже, распечатка их значений String будет отображать разные строки.

26
Carl Camera

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

Внутри дата хранится как Ticks, которая (в отличие от ответа @Carl Camera) отличается в зависимости от того, используете ли вы Now или UtcNow.

DateTime.UtcNow ведет себя как другие языки. Он устанавливает Ticks в значение по Гринвичу. Он также устанавливает Kind в Utc.

DateTime.Now изменяет значение Ticks на что было бы, если бы это было ваше время дня в часовом поясе GMT. Он также устанавливает Kind в Local.

Если вы отстаете на 6 часов (GMT-6), вы получите время по Гринвичу 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 <now" должен был быть верным (я даже добавил час, чтобы быть уверенным), но все равно был ложным.

Вы также можете увидеть "обходной путь", который заключается в простом преобразовании в универсальное время везде, где Kind не совпадает.

Мой прямой ответ на вопрос согласуется с рекомендацией принятого ответа о том, когда использовать каждый из них. Вы всегда должны пытаться работать с объектами DateTime, которые имеют Kind=Utc, за исключением случаев ввода-вывода (отображения и анализа). Это означает, что вы почти всегда должны использовать DateTime.UtcNow, за исключением случаев, когда вы создаете объект просто для его отображения и сразу же отбрасываете его.

14
Ted Bigham

DateTime понятия не имеет, что такое часовые пояса. Это всегда предполагает, что вы в вашем местном времени. UtcNow означает только "Вычесть мой часовой пояс из времени".

Если вы хотите использовать даты с учетом часового пояса, используйте DateTimeOffset, который представляет дату/время с часовым поясом. Мне пришлось научиться этому нелегкому пути.

6
Omer van Kloeten

"Простой" ответ на вопрос:

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

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

4
PapillonUK

Просто небольшое дополнение к пунктам, сделанным выше: структура DateTime также содержит малоизвестное поле с именем Kind (по крайней мере, я давно об этом не знал). Это в основном просто флаг, указывающий, является ли время местным или UTC; он не указывает реальное смещение от UTC для местного времени. Помимо того факта, что он указывает, с какими намерениями был создан элемент, он также влияет на способ работы методов ToUniversalTime () и ToLocalTime () .

4
Jan Zich
2
Sorin Comanescu

DateTime.UtcNow - это непрерывный однозначный временной масштаб, тогда как DateTime.Now не является непрерывным или однозначным. Основной причиной является летнее время, которое не относится к UTC. Таким образом, UTC никогда не переходит вперед или назад на час, тогда как местное время (DateTime.Now) делает. И когда он прыгает назад, то же самое время встречается дважды.

1
user1315023

DateTime.UtcNow - это универсальная шкала времени, в которой отсутствует летнее время. Так что UTC никогда не меняется из-за летнего времени.

Но DateTime.Now не является непрерывным или однозначным, поскольку он изменяется в соответствии с DST. Что означает DateTime.Now, одно и то же значение времени может происходить дважды, оставляя клиентов в замешательстве.

1
ChaiVan

Если вам нужно местное время для компьютера, на котором работает ваше приложение (например, CEST для Европы), используйте Сейчас. Если вы хотите универсальное время - UtcNow. Это просто вопрос ваших предпочтений - возможно, создание локального веб-сайта/отдельного приложения, которое вы хотели бы использовать в то время, которое пользователь выбрал - так зависит от его/ее настройки часового пояса - DateTime.Now.

Помните, для веб-сайта это настройка часового пояса сервера. Поэтому, если вы отображаете время для пользователя, либо получите его предпочтительный часовой пояс и сместите время (просто сохраните время Utc в базе данных и измените его) или укажите его UTC. Если вы забудете это сделать, пользователь может увидеть что-то вроде: опубликовано 3 минуса назад и затем время в будущем рядом с ним :)

0
kender