Данная статья была написана мной при работе в компании. Будет полезна для понимания времени разработчикам и аналитикам, а также для организации контрактов как best practice. Как выяснилось на практике, далеко не все представляют себе часовые пояса в разработке.
Команда работала с фреймворком Angular, ввиду этого будет он и упомянут. Утверждения правдивы и для React/Vue/... в схожих кейсах.
Небольшой голоссарий:
пайп (pipe) в Angular - функция приобразования в шаблоне; стоит понимать как чистую функцию
TZ - time zone - часовой пояс
DRY - don't repeat yourself
Ввиду сильного раздрая и неясности работы frontend и backend с датами и временем, были вынесены на обсуждение следующие договоренности.
Очень рекомендую к прочтению:
https://habr.com/ru/post/146109/
https://ru.wikipedia.org/wiki/%D0%92%D1%81%D0%B5%D0%BC%D0%B8%D1%80%D0%BD%D0%BE%D0%B5_%D0%BA%D0%BE%D0%BE%D1%80%D0%B4%D0%B8%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5_%D0%B2%D1%80%D0%B5%D0%BC%D1%8F - что такое UTC, GMT
Утверждение | Обоснование |
---|---|
1. Общение фронта с бэком всегда в формате iso-string с указанием часового пояса в формате UTC (Z - метка нулевого часового пояса) | - время в базе данных (должно) хранится в UTC по 0 поясу (не важно это iso-string или timestamp) - при получении даты с часовым поясом, отличным от 0, время, сохраняемое в базу, будет преобразовано к 0 часовому поясу - единый формат и шкала измерения данных предупреждают ошибки - UTC = международный, признанный формат данных - международная космическая станция использует UTC в качестве эталона времени |
2. Временные метки для данных везде где возможно брать на сервере, а не со стороны клиента | - время клиента далеко не всегда совпадает со временем сервера (имеется ввиду не часовой пояс UTC) - время клиента не всегда правдиво (неправильное время) |
3. Смещение по временному поясу для местного времени должно быть доступно в виде параметра смещения Пример: "+180" = "+03:00" = TZ Москва | - стандартный date pipe angular'а используют смещение для вывода данных - позволяет соблюсти формат UTC при общении с сервером Нужно уточнить формат смещения. Стандартно предполагается два варианта: - number ( смещение в часах "(+/-) * 60") - string (пример, Москва - "+03:00") Формат типа string используется в смещении времени date pipe в виде как есть (пример: "timeVar | date: "DD:MM:YYYY HH:mm : "+03:00" => 01.01.2020 11:32; UTC - 01.01.2020 08:32). |
4. На фронте оптимизировать правильный формат вывода данных в константу Пример: "DD:MM:YYYY HH:mm" | - унификация и выполнения принципа DRY |
5. Для преобразование времени на вывод использовать единый пайп | - унификация и выполнения принципа DRY |
6. Использование единого формата iso-string (в UTC) по всему приложению при общении между сущностями | - единый формат и шкала измерения данных предупреждают ошибки - перевод из iso-string в формат объекта данных просто написать самостоятельно или использовать библиотеку - iso-string "кушают" все (обязательно нужно помнить про указание часового пояса) |
Далее пример с использованием Angular (в целом будет понятен без знания)
Component - некая сущность с логикой (в примере - .ts файл)
Шаблон - html-файл, соединённый с Component
Интерполяция в Angular - механизм привязки переменной шаблона и логики (в примере: Component и шаблона; ссылка на определение)
FormControl - элемент Angular Forms; класс с методами set, get, подписки на измененные статусы и события и др.
Дано:
Компонент (Component) с шаблоном (html)
Сервер (backend)
formatVar = "DD.MM.YYYY HH:mm"
offsetVar = время клиента "+03:00" (предположим что лежит на клиенте, может приходить с сервера в том же запросе)
Путь отображения без промежуточных звеньев:
Component делает запрос на backend, приходит:
date: "2020-11-17T15:06:47.523Z" => переменная dateVar
Component сохраняет данные в переменные
В шаблоне (html) в блок (div) через интерполяцию вставляется переменная + angular date pipe
dateVar | date : formatVar : offsetVar (см. Дано)
вывод => 2020.11.17 18:06
Пользователь меняет переменную dateVar на 2020.11.17 20:00
Пользователь жмет "Сохранить"
Component преобразует дату к формату iso-string (стоит уточнить условия на практике, т.к. на момент написания статьи были нюансы)
если из FormControl поступает iso-string с указанием часового пояса, то формат готов
если из FormControl поступает string без часового пояса, то тут возможны варианты, но по факту все сведется к `new Date(var съедобного формата с часовым поясом).toISOstring()`
Component отправляет данные на backend в формате iso-string с TZ