Переход с Moment.js на Temporal API в JavaScript: практическое руководство
Разработчики JavaScript годами мучились с датами: встроенный Date API был настолько неудобен, что сообщество создало Moment.js, который стал стандартом де-факто. Но у Moment были свои недостатки — он тяжелый, мутабельный и не поддерживает современные стандарты вроде часовых поясов IANA. Теперь у нас

Разработчики JavaScript годами мучились с датами: встроенный Date API был настолько неудобен, что сообщество создало Moment.js, который стал стандартом де-факто. Но у Moment были свои недостатки — он тяжелый, мутабельный и не поддерживает современные стандарты вроде часовых поясов IANA. Теперь у нас есть Temporal — новый встроенный API, который исправляет все эти проблемы. Джо Аттарди, автор книги "JavaScript: The New Toys", поделился конкретными рецептами миграции с Moment на Temporal. Давайте разберем, что меняется и как переписать код без головной боли.
Что такое Temporal API и почему он заменяет Moment.js
Temporal — это новый глобальный объект в JavaScript, который предоставляет современные и неизменяемые способы работы с датами, временем, часовыми поясами и временными интервалами. В отличие от старого Date, Temporal разделяет понятия "дата" (Temporal.PlainDate), "время" (Temporal.PlainTime), "дата со временем" (Temporal.PlainDateTime) и "момент времени" (Temporal.Instant). Это избавляет от путаницы с часовыми поясами и делает код предсказуемым.
Moment.js, хоть и был популярен, имел ряд недостатков: он мутабельный (методы изменяют исходный объект), большой размер (даже с деревом тряской), не входит в стандартную библиотеку и требует отдельной установки. Temporal, напротив, встроен в движок, неизменяемый, поддерживает часовые пояса IANA и имеет понятный API. Google уже рекомендует Temporal для новых проектов.
Как переписать основные операции: от Moment к Temporal
Аттарди приводит конкретные примеры замены. Рассмотрим самые частые сценарии.
Как получить текущую дату и время в Temporal вместо Moment?
В Moment это moment(). В Temporal — Temporal.Now.plainDateISO() для даты, Temporal.Now.plainTimeISO() для времени, Temporal.Now.instant() для момента. Временная метка Unix: moment().unix() vs Temporal.Now.instant().epochMilliseconds / 1000. Разница очевидна: Temporal явно указывает, что именно вы хотите получить — дату, время или полный момент.
Как разобрать строку с датой в Temporal?
Moment: moment('2026-03-15'). Temporal: Temporal.PlainDate.from('2026-03-15'). Если строка содержит время и часовой пояс, используйте Temporal.Instant.from('2026-03-15T12:00:00Z') или Temporal.ZonedDateTime.from('2026-03-15T12:00:00[Europe/Moscow]'). Temporal строг к формату — он ожидает ISO 8601, что уменьшает ошибки парсинга.
Как отформатировать дату в Temporal?
Moment: moment().format('YYYY-MM-DD'). Temporal: date.toString() возвращает ISO-строку. Для кастомных форматов нужно использовать toLocaleString или стороннюю библиотеку, но Temporal сам по себе не предоставляет шаблонов форматирования — это осознанное решение команды, чтобы не раздувать API. Однако toLocaleString с опциями позволяет получить практически любой формат.
Как выполнять манипуляции с датами: add, subtract?
Moment: moment().add(7, 'days'). Temporal: date.add({ days: 7 }). Аналогично для месяцев, лет и т.д. Все методы возвращают новый объект. Например, date.subtract({ months: 1 }) работает аналогично. Неизменяемость гарантирует, что исходная дата не изменится.
Как сравнивать даты в Temporal?
Moment: moment().isBefore(other). Temporal: Temporal.PlainDate.compare(date1, date2) возвращает -1, 0 или 1. Либо используйте методы equals, since, until. Например, date1.since(date2) возвращает Duration, что удобно для вычисления разницы.
Технические детали: неизменяемость и часовые пояса
Главное отличие Temporal — неизменяемость. В Moment вы могли написать moment('2026-01-01').add(1, 'day') и получить новый объект, но оригинал оставался прежним (если не использовать мутирующие методы). В Temporal все методы возвращают новые объекты, а исходный не меняется. Это снижает количество багов.
Часовые пояса теперь обрабатываются через Temporal.ZonedDateTime, который хранит временную метку, часовой пояс и календарь. Это решает проблему Moment, где часовые пояса часто игнорировались или требовали плагина. Например, Temporal.ZonedDateTime.from('2026-03-15T12:00:00[Europe/Moscow]') корректно учитывает смещение и историю изменений часового пояса.
Temporal также поддерживает календари: по умолчанию ISO 8601, но можно использовать другие (например, исламский или еврейский). Это важно для интернационализации. Например, Temporal.PlainDate.from('2026-03-15', { calendar: 'islamic' }) создаст дату по исламскому календарю.
Кого затронет миграция и как подготовиться
Миграция коснется всех разработчиков, использующих Moment.js в существующих проектах. Для новых проектов лучше сразу использовать Temporal (если среда выполнения поддерживает его — современные браузеры и Node.js 22+ уже имеют поддержку). Для старых проектов потребуется рефакторинг, но он окупится меньшим количеством багов и лучшей производительностью.
Российским разработчикам стоит обратить внимание на часовые пояса: Temporal корректно обрабатывает перевод часов в России (например, отмена перехода на летнее время в 2014 году). Moment.js с плагином timezone тоже справлялся, но Temporal делает это нативно. Для подготовки можно начать с замены простых операций, постепенно переходя на сложные сценарии.
Что будет дальше: будущее работы с датами в JS
Temporal уже стабилизирован (stage 4) и включен в спецификацию ECMAScript. Сейчас идет активная поддержка в браузерах и Node.js. Ожидается, что через год-два Moment.js полностью устареет, и сообщество перейдет на Temporal. Для сложных случаев (например, работа с календарями или нестандартными временными интервалами) могут появиться библиотеки-надстройки, но базовый API уже покрывает 90% потребностей.
Итог
Temporal API — это долгожданное обновление, которое делает работу с датами в JavaScript удобной и безопасной. Переход с Moment.js не сложен: достаточно заменить вызовы на аналогичные методы Temporal, следуя рецептам Аттарди. Начните с малого: замените moment() на Temporal.Now.plainDateISO() и посмотрите, как тесты пройдут. Со временем вы оцените преимущества неизменяемости и правильной работы с часовыми поясами.