На главную

Firefox 139 — первый браузер с Temporal


Итак, официально: Firefox 139 станет первым браузером, который включает Temporal по умолчанию. Для JavaScript‑сообщества это важный рубеж. После почти трёх десятилетий с устаревшим Date мы, наконец, получаем современную, надёжную и экспрессивную модель работы с датами и временем прямо «из коробки» браузера, а не через сторонние библиотеки.

Это событие — результат энтузиазма волонтёров и открытого процесса стандартизации: предложение Temporal достигло Stage 3 TC39 в марте 2021 г., а уже через несколько недель в SpiderMonkey началась реализация. 99 патчей первоначального сета, сотни уточнений спецификации — и всё это во многом силами одного контрибьютора, André Bargull. История Temporal напоминает: индивидуальный вклад всё ещё меняет ход развития веб‑платформы.

А что не так с Date?

«Почему Date так странно работает?» Пора признаться — потому что этот объект был спроектирован в 1995 году для браузера, который сегодня вспоминают только историки. Времена изменились: у нас глобальные приложения, распределённые базы данных и строгие требования к часовым поясам. Решать старые задачи новым способом нам помогает Temporal.

Почему Date больше не справляется

Date хранит внутреннее число миллисекунд и пытается угадать ваш часовой пояс. В итоге мы сталкиваемся с мутирующими методами, индексируемыми с нуля месяцами и вечным страхом «а что будет на переходе на летнее время?». Каждая библиотека тащит свои обёртки — dayjs, date‑fns — и всё равно остаётся чувство: «Это костыль, а не решение».

Что даёт Temporal разработчику

  • Безопасность: нет неявных мутаций, все объекты неизменяемы.
  • Читаемость: названия методов говорят сами за себя — add, since, withTimeZone.
  • Детерминированность: никакой глобальной тайм‑зоны, всё явно.
  • Мощная типизация (если вы используете TypeScript): разные классы для точки во времени, календарной даты, длительности.

Примеры использования Temporal

  • Локальное «сейчас» в ISO 8601

    const now = Temporal.Now.plainDateTimeISO();
    console.log(now.toString()); // 2025-04-18T14:43:17.123
  • Перевод события в часовой пояс пользователя

    const releaseUTC = Temporal.ZonedDateTime.from('2025-05-12T16:00Z[UTC]');
    const userZone = Temporal.Now.timeZone(); // 'Europe/Stockholm'
    const inUserTZ  = releaseUTC.withTimeZone(userZone);
    
    console.log(inUserTZ.toString());
    // 2025-05-12T18:00+02:00[Europe/Stockholm]
  • Сколько дней между двумя датами

    const start = Temporal.PlainDate.from('2025-04-01');
    const end = Temporal.PlainDate.from('2025-04-18');
    
    const diff = end.since(start);
    console.log(diff.toString()); // P17D
    console.log(diff.days); // 17
  • Напоминание каждые две недели

    const interval = Temporal.Duration.from({ weeks: 2 });
    let next = Temporal.Now.plainDateISO();
    
    for (let i = 0; i < 3; i++) {
      next = next.add(interval);
      console.log(`Следующая встреча: ${next.toString()}`);
    }
  • «Через месяц» без эффекта 31‑го числа

    const invoiceDate = Temporal.PlainDate.from('2025-01-31');
    const dueDate = invoiceDate.add({ months: 1 }, { overflow: 'constrain' });
    
    console.log(dueDate.toString()); // 2025-02-28

Источники