Comments 25
Мне кажется научить рослин ругаться на неявное преобразование DateTime в DateTimeOffset не так уж и сложно, ибо вполне штатная ситуация.
Нет, тип DateTime
не имеет информации о TimeZone
. Он может быть трех вариантов: локальный (таймзоны сервера), UTC, unspecified. В нашей задаче встречаются времена со всех таймзон.
Самый простой пример — пусть вы пишете календарь для многонациональной корпорации. В офисе в Хабаровске есть ежедневный стендап команды уборщиков в 8 утра. Это время не таймзоны сервера (сервер в Москве) и не UTC. Его никак не преобразовать в DateTimeOffset
без дополнительной инфы о том, что это именно Хабаровск (то есть, собственно Offset). В DateTime этой инфы нет.
DateTime имеет только тип времени utc, местное или неопределённое.
DateTime.Now возвращает местное время по установкам системы.
IMHO, попахивает изобретением проблемы и попытками её решить…
Тем, что невозможно узнать локальное время события в таймзоне источника события.
На крайний склучай давайте указывать время по МСК…
IMHO, Вместо того, что бы узнать таймзону с клиента, автор изобретает велосипед на бэке. И да, попахивает изобретением проблемы и попытками её решить.
Ну дак и DateTimeOffset тут не поможет, потому что как уже писали выше, TimeZone и Offset разные вещи.
UTC+3 это может быть и MSK, а может быть и нет, а может MSK это UTC+4, до 2011 года, вдруг MSK станет UTC+5 в 2019?
Все что даст узнать DateTimeOffset, это оффсет в котором произошло событие, но никак и время в какой-либо таймзоне.
Пример выше про календарь опять же не решается с помощью DateTimeOffset, потому как запланированная встреча на 2020 год в 8 утра по MSK может поломаться, т.к. правительство решит опять переходить на летнее/зимнее время, и часовой пояс для MSK изменится, а на момент создания вы полагаетесь просто на +3. Посмотрите диалог создания событий в гугл календаре, там выбирается не оффсет, а именно таймзона.
Таким образом, чтобы узнать локальное время в таймзоне, надо хранить, таймзону, как ни странно!
Надо в базе и бекенде хранить DateTimeOffset. В новых местах мы так и делаем. Почему недостаточно UTC — см выше про хабаровск и уборщиков.
И вообще я тут проблемы не вижу. Смотрим исходный код:
public static implicit operator DateTimeOffset (DateTime dateTime) {
return new DateTimeOffset(dateTime);
}
public static DateTimeOffset Now {
get {
return new DateTimeOffset(DateTime.Now);
}
}
То есть вызов DateTimeOffset.Now аналогичен DateTimeOffset(DateTime.Now) и DateTimeOffset Event = DateTime.Now.
так учитывает локальную зону компьютера, где идёт преобразование.
Да, и это нас не устраивало. В нашем кейсе DateTime могут быть не только в этой локальной зоне, а еще и в другой. В какой — в каждом случае разной, программист должен подумать. Чтобы он не забыл подумать, нам важно, чтобы неявного преобразования не было, а было только явное.
Я вам и не говорю, что нужно использовать DateTime. Использование DateTimeOffset полностью оправдано и вы храните в базах именно этот тип, но как возможность локального неявного преобразования может подпортить вам данные? При добавлении в базу новых данных всё равно будет учитываться временная зона локального компьютера, откуда добавляется.
Как человек с опытом работы с временем и зонами, могу высказать имхо. Храните всё в utc. Всегда. Никогда не храните локальное время ни в какой базе. Utc отражает момент времени, единый для всей Земли (минус релятивизм).
Если нужно отобразить время пользователю, используйте перевод в локальное время на клиенте.
В исключительно редком случае, когда нужно хранить ощущаемое пользователем время (показания на часах на стене пользователя; в стиле календаря в конкретной таймзоне, что само по себе немного странно), храните локальное время и таймзону, в совершенно отдельном типе. Эта конструкция не задаёт момент времени, потому что её смысл может меняться вместе с оффсетом таймзоны.
P.S. Опыт с двух сторон: разработка мобильного приложения для продажи авиабилетов — народ пару раз приезжал к вылету на час раньше/позже из-за забавных особенностей таймзон и Российского законодательства; и работы в международной компании, где я скорее назову текущее время utc, чем локальное, в ответ на вопрос "который час?".
Лично я на 100% согласен с gurux13 — в базе только в UTC.
Выше тоже писали про локальное время компьютера (так понимаю, сервера), где происходит преобразование. Хорошо, если у вас один сервер, стоящий в соседней кладовке, а если система распределённая? Вы не можете предсказать, где и когда будет обработан данный запрос пользователя: может в Штатах, может в Европе, может в Японии…
Другой пример: в одной конторе я был в команде, которая занималась представлением демо и PoC потенциальным клиентам по всему миру. Приходилось летать с системой, установленной на ноут, чтобы всё показывать (а порой и допиливать или даже реализовывать совершенно новый функционал, который только что стукнул в голову потенциальному клиенту). Ну прилетел я, положим, в Сингапур — локальное время «перевелось»… а потом возвращаюсь домой и нужно проанализировать логи или «проиграть» то, что было показано ранее, на месте. А время-то опять «переехало». И начинается ад.
Так что не — в базе хранить всё только в UTC и на бэкенде оперировать тоже только им.
DateTimeOffset — это не локальное время. Это абсолютное плюс оффсет (указывающий локальное время источника).
DateTimeOffset… прекрасно поддерживается MS SQL и Entity Framework
Как решена проблема хранения DateTimeOffsetStrict в БД?
DateTimeOffset(Strict)