Введение в JavaScript Temporal API
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами на чистом JS — это большая головная боль. Реализация объекта Date() была скопирована непосредственно из Java в 1995 году. Два года спустя Java отказалась от нее, но она осталась в JavaScript для обратной совместимости.
Проблемы, с которыми мы сталкиваемся при использовании Date()
:
- он поддерживает только UTC и местное время пользователя
- нет поддержки негригорианских календарей
- переход на летнее время непредсказуем
- синтаксический анализ дат из строк ненадежен
- очень не удобное АПИ
- Объекты
Date
изменяемы (mutable): то есть экземпляр объекта Date будет меняться по мере применения методов.
Раньше самой популярной альтернативой была библиотека Moment.js. Однако ее развитие было остановлено и она было переведено в режим обслуживания и теперь не должна использоваться в новых проектах. Они рекомендуют несколько альтернатив, но каждая из них имеет свои плюсы и минусы.
Объект Date()
нельзя удалить из JavaScript, но новое АПИ работы со временем находится на этапе 3 в процессе утверждения стандартов TC39.
Объект Temporal
Temporal
— это статический глобальный объект верхнего уровня (такой же как Math
).
Его основные цели:
- предсказуемое поведение в разных браузерах и во время выполнения
- более простое API для вычисления даты и времени
- поддержка негригорианских календарей
- поддержка всех часовых поясов, включая арифметику перехода на летнее время
- парсинг строго определенных строк ISO-8601
- сделать все экземпляры объектов неизменяемыми
API является всеобъемлющим и может измениться, но вы можете рассчитывать на следующие ключевые функции в какой-то момент в ближайшем будущем.
Текущая дата и время
Temporal.now
возвращает текущую дату/время, которые можно передать другим методам для предоставления дополнительной информации. Например:
// exact time since the Unix epoch on 1 Janary, 1970 UTC Temporal.Now.instant(); Temporal.Now.instant().epochSeconds; Temporal.Now.instant().epochMilliseconds; // current time zone Temporal.Now.timeZone(); // time in current location, e.g. // 2021-09-18T04:17:48.435068431-04:00[America/New_York] Temporal.Now.zonedDateTimeISO(); // time in another time zone, e.g. // 2021-09-18T09:17:48.438068435+01:00[Europe/London] Temporal.Now.zonedDateTimeISO('Europe/London');
Создание инстанса Даты/Время
Объект Temporal.Instant
представляет один момент времени с точностью до наносекунды. Его можно создать из строк в формате ISO 8601 или нескольких секунд, миллисекунд или микросекунд:
const t1 = Temporal.Instant.from('2021-03-30T01:45:00+01:00[Europe/Berlin]'), t2 = Temporal.Instant.from('2021-04-01T02:00+01:00'), t3 = Temporal.Instant.fromEpochSeconds(1.0e8), t4 = Temporal.Instant.fromEpochMilliseconds(1.0e10), t5 = Temporal.Instant.epochNanoseconds(1.0e12);
Создание даты/времени с учетом тайм зоны
Объект Temporal.ZonedDateTime
представляет часовой пояс и дату/время с учетом календаря на момент, когда это произошло (или произойдет) в определенном регионе. Можно использовать самые разные конструкторы:
new Temporal.ZonedDateTime( 1234567890000, // epoch nanoseconds Temporal.TimeZone.from('America/Los_Angeles'), // timezone Temporal.Calendar.from('iso8601') // default calendar ); Temporal.ZonedDateTime.from('2025-12-07T03:24:30+02:00[Africa/Cairo]'); Temporal.Instant('2022-08-05T20:06:13+05:45').toZonedDateTime('+05:45'); Temporal.ZonedDateTime.from({ timeZone: 'America/New_York' year: 2025, month: 1, day: 7, hour: 9, minute: 30, second: 1, millisecond: 2, microsecond: 3, nanosecond: 4 });
Создание простых дат и времени
Не всегда необходимо использовать точные моменты времени, поэтому Temporal API предоставляет объекты, не зависящие от часовых поясов. Их можно использовать для более простых мероприятий, таких как встреча сегодня в 14:00.
Temporal.PlainDateTime
относится к календарной дате и времениTemporal.PlainDate
относится к определенной календарной датеTemporal.PlainTime
относится к определенному времени сутокTemporal.PlainYearMonth
относится к дате без компонента дня, например «встреча в апреле 2021 года».Temporal.PlainMonthDay
относится к дате без компонента года — например, «день Пи — 14 марта».
Все имеют похожие конструкторы:
// create a new PlainDateTime // both are 4 May 2021 at 1:14pm and 15 seconds new Temporal.PlainDateTime(2021, 5, 4, 13, 14, 15); Temporal.PlainDateTime.from('2021-05-04T13:14:15'); // create a new PlainDate // both are 4 May, 2021 new Temporal.PlainDate(2021, 5, 4); Temporal.PlainDate.from('2021-05-04'); // create a new PlainTime // both are 1:14pm and 15 seconds new Temporal.PlainTime(13, 14, 15); Temporal.PlainTime.from('13:14:15'); // create a new year PlainYearMonth // both are April 2021 new Temporal.PlainYearMonth(2021, 4); Temporal.PlainYearMonth.from('2019-04'); // create a new PlainMonthDay // both are 14 March new Temporal.PlainMonthDay(3, 14); Temporal.PlainMonthDay.from('03-14');
Извлечение значений
Все объекты Temporal
могут возвращать дискретные значения об определенной дате/времени. Например, используя ZonedDateTime
:
const t1 = Temporal.ZonedDateTime.from('2025-12-07T03:24:30+02:00[Africa/Cairo]'); t1.year; // 2025 t1.month; // 12 t1.day; // 7 t1.hour; // 3 t1.minute; // 24 t1.second; // 30 t1.millisecond; // 0 t1.microsecond; // 0 t1.nanosecond; // 0
К другим полезным свойствам относятся:
dayOfWeek
(1 для понедельника и далее до 7 для воскресенье)dayOfYear
(от 1 до 365 или 366)weekOfYear
(от 1 до 52, или иногда 53)daysInMonth
(28, 29, 30, or 31)daysInYear
(365 или 366)inLeapYear
(true
илиfalse
)
Сравнение и сортировка дат
Все объекты Temporal
можно сравнивать с помощью функции compare(), которая возвращает целое число. Например, чтобы сравнить два объекта ZonedDateTime
:
// returns: // -1 if t1 is before t2 // 0 if t1 and t2 are the same // 1 is t1 is after t2 Temporal.ZonedDateTime.compare(t1, t2);
compare() можно использовать как функцию Array sort() для упорядочения даты/времени в возрастающем хронологическом порядке (от самого раннего к последнему):
const t = [ '2022-01-01T00:00:00+00:00[Europe/London]', '2022-01-01T00:00:00+00:00[Africa/Cairo]', '2022-01-01T00:00:00+00:00[America/New_York]' ].map( d => Temporal.ZonedDateTime.from(d) ) .sort( Temporal.ZonedDateTime.compare );
Расчет даты
Предусмотрено несколько методов для выполнения вычислений даты для любого объекта Temporal. Все они возвращают новый Temporal того же типа при передаче объекта Temporal.Duration
, определяющего период в годах, месяцах, днях, часах и т. д.
const t1 = Temporal.ZonedDateTime.from('2022-01-01T00:00:00+00:00[Europe/London]'); // add 8 hours 30 minutes t1.add({ hours: 8, minutes: 30 }); // subtract 5 days t1.subtract({ days: 5 }); // round to nearest month t1.round({ smallestUnit: 'month' });
Обратите внимание, что обычные даты Plain
и время могут переноситься. Например, добавление 24 часов к любому PlainTime
вернет объект, содержащий идентичное значение.
Методы
и until()
since()
возвращают объект Temporal.Duration, описывающий время до или после определенной даты/времени:
// mounths until t1 t1.until().months; // weeks since t1 t1.since().weeks;
Наконец, метод equals()
может определить, эквивалентны ли два значения даты/времени:
const d1 = Temporal.PlainDate.from('2022-01-31'); d2 = Temporal.PlainDate.from('2021-01-31'); d1.equals(d2); // false
Форматирование дат с помощью API интернационализации
Хотя JavaScript Intl
(Internationalization) API не является частью Temporal API, он предоставляет конструктор DateTimeFormat()
, который можно использовать для форматирования объектов Temporal или Date:
const d = new Temporal.PlainDate(2021, 3, 14); // 3/14/2021 new Intl.DateTimeFormat('en-US').format(d); // 14/3/2021 new Intl.DateTimeFormat('en-GB').format(d); // miércoles, 14 de abril de 2021 new Intl.DateTimeFormat('es-ES', { dateStyle: 'full' }).format(d);
О времени?
Объект Date()
был причиной разочарования разработчиков в течение четверти века. Хотя нет никаких гарантий, что Temporal
быстро станет стандартной функцией, будущее дат JavaScript выглядит немного ярче.
Вы можете попробовать Temporal уже сегодня с помощью экспериментального полифилла, но не используйте его в производственной среде (пока)!
Больше информации:
- Temporal proposal documentation
- Temporal Cookbook — примеры использования