Дата-время, таймзоны...
- Алик Ким
- 21 дек. 2022 г.
- 3 мин. чтения
Обновлено: 28 апр. 2023 г.
поизучал немного эту тему.
общее впечатление: даты-время - очень опасная штука под крайне невинной оболочкой. надо ж, никогда особо не задумывался об этом. если пишешь международное приложение - с этими тварями нужно обращаться крайне осторожно.
https://apiux.com/2013/03/20/5-laws-api-dates-and-times/ - полезная статья с рекомендациями. принципы работы с датами, согласно этой статье:
Use ISO-8601 for your dates //это - строки вида "2022-01-13T16:25:35.1250000+06:00" - дата-время + смещение относительно UTC-0, с учетом которого это время и задано.
Accept any timezone
Store it in UTC
Return it in UTC
Don’t use time if you don’t need it
но аргументация в последнем совете слабовата: если даже отправить дату в UTC без указания времени (то есть, если это будет UTC-полночь) - это не убережет наше значение от изменения даты при преобразовании в локальное время. например, если преобразовать UTC-полночь в UTC-08 - получится 16:00 предыдущего дня.
ну и ,вот, пример, когда нам нужны только даты, без времени: менеджер какого-нибудь работающего по всему миру интернет-магазина, находясь в Алмаате (UTC+6), захочет посмотреть все продажи, сделанные за вчера - по сути он ожидает увидеть продажи начиная с 6 утра по гринвичу за вчерашний день и по 6 утра по гринвичу сегодняшнего дня.
то есть для того, чтоб отфильтровать продажи правильно - нужно с клиента (допустим, это - браузер/джаваскрипт) отправить дату-время, соответствующую полуночи для обеих дат диапазона.
по факту это время соответствует 6 утра по гринвичу.
а так как даты в БД у нас по-хорошему хранятся тоже в UTC0-виде - все должно отфильроваться без проблем, будут найдены просто продажи между 6 утра UTC0 за вчера и за сегодня.
а вот при отсечении временнОй части из значений даты-времени - начались бы проблемы, потому что часовой пояс у сервера может не сответствовать часовому поясу клиента, а, значит, как определить, в какой момент для клиента наступает новая дата... и пошло-поехало.
ну а когда пишешь приложение, которое будет использоваться в рамках одного региона/таймзоны - все ужасы ночи исчезают, все становится просто и привычно, дата - один из простых типов данных вроде целого числа или строки🙂
а, еще нюанс/к размышлению (об этом пишется в этой статье): может быть дата/время, не привязанное к определенной точке на шкале истории. приводятся примеры: момент начала праздника 14 февраля - в каждой таймзоне он свой. или какое время считать слишком ранним (для звонка, например). статья - про JS, поэтому тут советуют такие ситуации разруливать на строках.
а мне вот тут на ум, как раз, пришел DateTime.Kind = Unspecified (см. ниже), может, он - как раз, для таких случаев
C#:
DateTime.Now - создает дату-время с местным UTC. чтоб привести к UTC0 - ToUniversalTime()
как преобразовать дату-время в другую таймзону: TimeZoneInfo.ConvertTime(dt, TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time"));
где "Central Standard Time": в системе есть список таймзон - вот это - значение ИД такой таймзоны. вот тут они: https://howtomanagedevices.com/windows-10/1774/list-of-windows-10-time-zone-codes-tzutil/
*кстати, вот интересно: а в Linux же свой набор таймзон, наверное? как-то это не очень хорошо для кроссплатформенности... ну уже не стал разбираться.
обращаю внимание: "таймзона" не равно "смещение": в одной таймзоне в разное время года может быть разное смещение относительно UTC0 засчет перехода на зимнее/летнее время
TimeZoneInfo.ConvertTimeToUtc - конвертация в UTC
у DateTime есть свойство Kind. его возможные значения: Local, Utc и Unspecified.
его можно поменять вручную, тогда у даты-времени сменится смещение, а значение, собственно, времени, останется тем же.
в целом нет причин так делать, наверное.
вот так можно получить ISO-8601-строку:
DateTime.ToString("o")
Javascript:
тут дается расклад
new Date().toISOString() - преобразует в строку ISO-8601, при чем, конвертит в UTC-0
объекты Date всегда хранят дату-время в UTC0. но все методы приводят к текущей таймзоне. кроме специализированных , типа toISOString. еще, в частности, JSON.Stringify преобразует дату-время в UTC-строку
SQL Server:
есть тип данных datetimeoffset - как я понял, он предназначен для хранения даты-времени, включая смещение (ну , то есть, то же, что хранится в C#-DateTime)
API:
для API-вызовов нужно использовать ISO-8601. WebAPI прекрасно понимает этот формат.
нужно принимать в любых таймзонах, для хранения советуют преобразовывать в UTC-0
полезные ссылки:
https://apiux.com/2013/03/20/5-laws-api-dates-and-times/ - предлагаются принципы работы с датами
https://howtomanagedevices.com/windows-10/1774/list-of-windows-10-time-zone-codes-tzutil/ - список тайм-зон Windows
https://dba.stackexchange.com/questions/39421/how-to-handle-timezone-properly-in-sql-server - некоторые полезные рассуждения
https://www.ursahealth.com/new-insights/dates-and-timezones-in-javascript - расклад по датам-времени в JS + полезные рассуждения
Bình luận