Дата без сюрпризов: ISO для хранения и Intl для отображения

2 мин чтения

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

От момента времени к подписи в интерфейсе
  1. Исходное значениеРазличаем момент времени и календарную дату
  2. Хранение и обменПередаём момент в ISO с указанием смещения
  3. ОтображениеIntl форматирует дату в выбранном часовом поясе

Событие произошло один раз, но в Москве это уже понедельник, а у другого пользователя ещё воскресенье. С датами ошибок будет меньше, если сначала решить, что именно мы храним: момент события или день в календаре. Затем отдельно выбрать часовой пояс и формат показа. Для этого подойдут ISO-строки и Intl.DateTimeFormat.

Момент передаём с часовым поясом

const created = new Date('2024-05-20T09:00:00Z');
const wireValue = created.toISOString();
const formatter = new Intl.DateTimeFormat('ru-RU', {
  timeZone: 'Europe/Moscow',
  dateStyle: 'medium',
  timeStyle: 'short'
});
console.log(wireValue);
console.log(formatter.format(created));

ISO-строка содержит однозначный момент, а форматирование задаёт правила показа. Часовой пояс указан явно, поэтому вид интерфейса не зависит от настройки машины, на которой выполнен JavaScript. Локализованную строку удобно читать, но неудобно использовать как формат обмена между сервисами.

Календарная дата не обязана быть моментом

Значение 2024-05-20 для даты договора можно хранить как отдельную календарную дату. Не добавляйте к нему полночь в случайном поясе только ради создания Date: при последующем преобразовании пользователь может увидеть предыдущий день. Правила превращения такой даты в момент должны задаваться бизнес-логикой.

Отображение не меняет исходные данные

Intl.DateTimeFormat не переносит запись в базе в другой часовой пояс. Он только формирует представление. Для группировки по рабочему дню организации используйте тот же явно выбранный пояс на сервере или в запросе, а не группируйте по UTC и затем меняйте подпись.

Особенно внимательно проверьте время около полуночи, ввод из другого пояса и ошибочные даты. Там, где переводят часы, бывают повторяющиеся или пропущенные местные часы — для них нужны отдельные правила. Хранение момента в UTC помогает, но не решает за приложение, как трактовать такой ввод.

Источники и дальнейшее чтение