Проблема не в том, что JavaScript не умеет работать с датами. Проблема в Date — он слишком легко позволяет скрыть разницу между принципиально разными вещами. Всё кажется простым, пока не появляются timezone, переход через полночь, пользователь в другом регионе или API, которые по-разному трактуют одну и ту же строку.

Temporal — это TC39-предложение, которое дошло до финальной стадии стандартизации. Но поддержка в браузерах пока еще неровная: на MDN API все еще помечен как limited availability, так что в production нужно проверять совместимость или использовать polyfill. Оно предлагает не просто новый набор методов. Оно предлагает другую модель мышления — и именно она полезна уже сейчас, даже если ты ещё не используешь её.

Дальше — почему Date структурно создаёт эту путаницу, какие три типа времени выделяет Temporal и как применить эту модель к реальному коду уже сегодня, не дожидаясь полного перехода на новый API.

Почему тема дат снова на повестке

На практике ошибки со временем почти никогда не выглядят как интересная инженерная задача. Они выглядят как:

  • встреча в календаре съехала на час;
  • дедлайн в интерфейсе показывается не в тот день;
  • отчет не совпадает между фронтендом и бэкендом;
  • дата рождения внезапно съехала из-за timezone;
  • фильтр по дню работает правильно только в одном регионе.

Проблема в том, что Date долго подталкивал разработчиков к слишком общей модели. У тебя есть объект, в котором сразу смешаны календарная дата, момент времени, timezone-интерпретация и форматирование. Это удобно на старте и дорого в поддержке.

Что именно не так с Date

Date плох не потому, что им невозможно пользоваться. Он плох тем, что слишком легко скрывает разницу между разными сущностями.

Например, это разные вещи:

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

Но в коде они очень быстро начинают жить в одном типе.

Дата рождения и timestamp — не одно и то же

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

Срок публикации и локальное отображение — тоже разные задачи

Если API хранит точный момент публикации, это одно. Если интерфейс показывает человеку “7 марта” в его локальном часовом поясе, это уже другой слой задачи. И как только эти слои смешиваются, начинается путаница.

Чем Temporal меняет модель мышления

Самая полезная идея Temporal — не в конкретных именах API, а в том, что он разделяет сущности, которые раньше было слишком легко слепить вместе.

Условно:

  • Instant — это момент времени;
  • PlainDate — это дата без timezone;
  • ZonedDateTime — это дата и время в конкретной зоне.

Даже если ты прямо сейчас не пишешь код на Temporal каждый день, сама эта модель уже помогает задавать правильные вопросы.

Какой тип времени у меня на самом деле?

Это главный вопрос, который слишком редко задают в обычном JavaScript-коде.

Не “как это отформатировать”, а именно “что это за сущность”.

  • Дата события без времени?
  • Момент платежа?
  • Локальное время для пользователя?
  • Срок действия оффера в конкретном регионе?

Как только ответ становится явным, код обычно упрощается.

Где это особенно полезно фронтенду

Формы и пользовательский ввод

Фронтенд очень часто первым встречает данные, связанные со временем. И именно здесь проще всего заложить ошибку в модель.

Если форма собирает календарную дату, не надо относиться к ней как к полному timestamp. Иначе потом начинается лишняя сериализация, преобразования и споры о том, где именно произошел сдвиг.

API-границы

Тема особенно важна рядом с GraphQL и любыми контрактами между фронтендом и сервером. Если на границе неясно, передается ли plain date, instant или локализованное время, баги появляются не сразу, а через цепочку интеграций.

Фильтры, сортировки и отчеты

Во многих интерфейсах задача звучит как “покажи все за сегодня”, “отсортируй по дате”, “отобрази дедлайн”. На самом деле за этим стоят разные правила интерпретации времени. Если они не выделены явно, интерфейс рано или поздно начинает спорить сам с собой.

Как использовать идеи Temporal уже сейчас

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

1. Перестань называть все подряд просто date

Если поле хранит точный момент времени, назови это как publishedAt, createdAt, expiresAt. Если это календарная дата, не делай вид, что это то же самое.

2. Разделяй хранение и отображение

Хранение — это одна задача. Форматирование для человека — другая. Когда они перепутаны, код почти всегда становится хрупким.

3. Уточняй timezone на границе системы

Если данные приходят из API, полезно сразу понимать: это UTC-момент, локальная дата, дата без зоны или что-то еще. Чем раньше это становится явным, тем меньше потом сюрпризов в UI.

4. Не нормализуй все в Date “на автомате”

Иногда лучше дольше сохранить исходную модель данных, чем мгновенно превратить ее в универсальный, но расплывчатый тип.

Итог

Разговор о Temporal полезен не тем, что предлагает еще один набор методов для работы с датами. Он полезен тем, что заставляет перестать путать разные типы времени в одной абстракции.

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