В разделе события на sf4answers пользователи вводят адрес для события, а также дату начала и дополнительную дату окончания. Это время преобразуется в datetimeoffset
на сервере SQL, который учитывает смещение от UTC.
Это та же проблема, с которой вы сталкиваетесь (хотя вы придерживаетесь другого подхода, поскольку вы используете DateTime.UtcNow
); у вас есть местоположение, и вам нужно перевести время из одного часового пояса в другой.
Есть две основные вещи, которые я сделал, которые работали на меня. Во-первых, всегда используйте DateTimeOffset
структура . Он учитывает смещение от UTC, и если вы сможете получить эту информацию от своего клиента, это сделает вашу жизнь немного проще.
Во-вторых, при выполнении переводов, предполагая, что вы знаете местоположение / часовой пояс, в котором находится клиент, вы можете использовать общедоступную базу данных информационных часовых поясов для перевода времени из UTC в другой часовой пояс ( или триангулируйте, если хотите, между двумя часовыми поясами). Самое замечательное в базе данных tz (иногда ее называют база данных Олсона ) состоит в том, что она учитывает изменения часовых поясов в истории; получение смещения является функцией даты, на которую вы хотите получить смещение (просто посмотрите на Закон об энергетической политике 2005 года , который изменил даты вступления в силу летнего времени в США. ).
Имея базу данных в руках, вы можете использовать ZoneInfo (база данных tz / база данных Олсона) .NET API . Обратите внимание, что бинарного дистрибутива нет, вам придется загрузить последнюю версию и скомпилировать ее самостоятельно.
На момент написания этой статьи он в настоящее время анализирует все файлы в последнем дистрибутиве данных (на самом деле я запускал его для ftp: //elsie.nci.nih.gov/pub/tzdata2011k.tar. файл gz от 25 сентября 2011 г., в марте 2017 г. вы получите его по https://iana.org/time-zones или по ftp: //fpt.iana.org/tz/releases/tzdata2017a.tar. GZ ).
Таким образом, на sf4answers после получения адреса он геокодируется в комбинацию широта / долгота, а затем отправляется стороннему веб-сервису для получения часового пояса, соответствующего записи в базе данных tz. Отсюда время начала и окончания преобразуется в DateTimeOffset
экземпляров с правильным смещением UTC, а затем сохраняется в базе данных.
Что касается работы с SO и веб-сайтами, это зависит от аудитории и того, что вы пытаетесь отобразить. Если вы заметили, большинство социальных сайтов (и SO, и раздел событий на sf4answers) отображают события в относительно времени, или, если используется абсолютное значение, обычно это UTC.
Однако, если ваша аудитория ожидает местное время, то использование DateTimeOffset
вместе с методом расширения, который использует часовой пояс для преобразования, было бы просто замечательно; тип данных SQL datetimeoffset
будет преобразован в .NET DateTimeOffset
, который затем вы можете получить универсальное время для использования GetUniversalTime
метода . Оттуда вы просто используете методы класса ZoneInfo
для преобразования из UTC в местное время (вам нужно будет проделать небольшую работу, чтобы преобразовать его в DateTimeOffset
, но это достаточно просто сделать).
Где сделать преобразование? Это стоимость, которую вы должны будете заплатить где-то , и нет "лучшего" способа. Я бы выбрал вид, хотя со смещением часового пояса как часть модели представления, представленной представлению. Таким образом, если требования к представлению изменяются, вам не нужно менять модель представления, чтобы учесть это изменение. Ваш JsonResult
будет просто содержать модель с IEnumerable<T>
и смещением.
На стороне ввода, используя модель переплета? Я бы сказал, ни за что. Вы не можете гарантировать, что все даты (сейчас или в будущем) должны быть преобразованы таким образом, это должно быть явной функцией вашего контроллера для выполнения этого действия. Опять же, если требования изменяются, вам не нужно настраивать один или несколько ModelBinder
экземпляров для корректировки вашей бизнес-логики; - это бизнес-логика, что означает, что она должна быть в контроллере.