Проблема не в том, что JavaScript не умеет работать с датами. Проблема в Date — он слишком легко позволяет скрыть разницу между принципиально разными вещами. Всё кажется простым, пока не появляются часовые пояса, переход через полночь, пользователь в другом регионе или API, которые по-разному трактуют одну и ту же строку.
Temporal — это TC39-предложение, которое дошло до Stage 3 — предфинальной стадии стандартизации. Но поддержка в браузерах пока еще неровная: на MDN API все еще помечен как ограниченно доступный, так что в проде нужно проверять совместимость или использовать polyfill. Temporal предлагает не просто новый набор методов. Он предлагает другую модель мышления — и именно она полезна уже сейчас, даже без ежедневного использования нового API.
Дальше — почему Date структурно создаёт эту путаницу, какие три типа времени выделяет Temporal и как применить эту модель к реальному коду уже сегодня, не дожидаясь полного перехода на новый API.
- Почему тема дат снова на повестке
- Что именно не так с Date
- Чем Temporal меняет модель мышления
- Где это особенно полезно фронтенду
- Как использовать идеи Temporal уже сейчас
- Итог
Почему тема дат снова на повестке
На практике ошибки со временем почти никогда не выглядят как интересная инженерная задача. Они выглядят как:
- встреча в календаре съехала на час;
- дедлайн в интерфейсе показывается не в тот день;
- отчет не совпадает между фронтендом и бэкендом;
- дата рождения внезапно съехала из-за часового пояса;
- фильтр по дню работает правильно только в одном регионе.
Проблема в том, что Date долго подталкивал разработчиков к слишком общей модели. В одном объекте сразу смешаны календарная дата, момент времени, интерпретация часового пояса и форматирование. Это удобно на старте и дорого в поддержке.
Что именно не так с Date
Date плох не потому, что им невозможно пользоваться. Он плох тем, что слишком легко скрывает разницу между разными сущностями.
Например, это разные вещи:
- конкретный момент времени;
- дата без привязки к часовому поясу;
- локальное время в конкретной зоне;
- период, который пользователь ожидает видеть как “сегодня”.
Но в коде они очень быстро начинают жить в одном типе.
Дата рождения и метка времени — не одно и то же
Если пользователь вводит дату рождения, метка времени обычно не нужна. Нужна календарная дата как таковая. Как только она превращается в момент времени, в игру незаметно входит часовой пояс, и логика уже может поехать.
Срок публикации и локальное отображение — тоже разные задачи
Если API хранит точный момент публикации, это одно. Если интерфейс показывает человеку “7 марта” в его локальном часовом поясе, это уже другой слой задачи. И как только эти слои смешиваются, начинается путаница.
Чем Temporal меняет модель мышления
Самая полезная идея Temporal — не в конкретных именах API, а в том, что он разделяет сущности, которые раньше было слишком легко слепить вместе.
Условно:
Instant— это момент времени;PlainDate— это дата без часового пояса;ZonedDateTime— это дата и время в конкретной зоне.
Даже без ежедневной работы с Temporal эта модель уже помогает задавать правильные вопросы.
Какой тип времени у меня на самом деле?
Это главный вопрос, который слишком редко задают в обычном JavaScript-коде.
Не “как это отформатировать”, а именно “что это за сущность”.
- Дата события без времени?
- Момент платежа?
- Локальное время для пользователя?
- Срок действия оффера в конкретном регионе?
Как только ответ становится явным, код обычно упрощается.
Где это особенно полезно фронтенду
Формы и пользовательский ввод
Фронтенд очень часто первым встречает данные, связанные со временем. И именно здесь проще всего заложить ошибку в модель.
Если форма собирает календарную дату, не надо относиться к ней как к полной метке времени. Иначе потом начинается лишняя сериализация, преобразования и споры о том, где именно произошел сдвиг.
API-границы
Тема особенно важна рядом с GraphQL и любыми контрактами между фронтендом и сервером. Если на границе неясно, передается ли plain date, instant или локализованное время, баги появляются не сразу, а через цепочку интеграций.
Фильтры, сортировки и отчеты
Во многих интерфейсах задача звучит как “покажи все за сегодня”, “отсортируй по дате”, “отобрази дедлайн”. На самом деле за этим стоят разные правила интерпретации времени. Если они не выделены явно, интерфейс рано или поздно начинает спорить сам с собой.
Как использовать идеи Temporal уже сейчас
Даже если проект пока не переезжает на новый API, многое можно улучшить уже сегодня.
1. Не называть все подряд просто date
Если поле хранит точный момент времени, названия вроде publishedAt, createdAt, expiresAt описывают его точнее. Если это календарная дата, не стоит делать вид, что это то же самое.
2. Разделение хранения и отображения
Хранение — это одна задача. Форматирование для человека — другая. Когда они перепутаны, код почти всегда становится хрупким.
3. Уточнение часового пояса на границе системы
Если данные приходят из API, полезно сразу понимать: это UTC-момент, локальная дата, дата без зоны или что-то еще. Чем раньше это становится явным, тем меньше потом сюрпризов в UI.
4. Не нормализовать все в Date “на автомате”
Иногда лучше дольше сохранить исходную модель данных, чем мгновенно превратить ее в универсальный, но расплывчатый тип.
Итог
Разговор о Temporal полезен не тем, что предлагает еще один набор методов для работы с датами. Он полезен тем, что заставляет перестать путать разные типы времени в одной абстракции.
Наиболее конкретный следующий шаг — три реальных сценария из проекта (например, дата рождения, дедлайн и метка времени публикации) и честный вопрос: живут ли они под одной и той же моделью данных, или каждый из них требует своего типа? Очень часто уже этот разбор показывает, где будущая ошибка не в часовом поясе, а в том, что код изначально неверно описывает время.