Форматирование с временными зонами

Работа с временными зонами в Moment.js строится вокруг двух ключевых аспектов: преобразования времени между зонами и корректного форматирования с учётом смещений и идентификаторов IANA. Базовая библиотека Moment.js работает в локальной временной зоне окружения или в UTC, однако полноценная поддержка часовых поясов реализуется через расширение moment-timezone.


Moment.js хранит момент времени как количество миллисекунд с эпохи Unix (UTC). Это означает, что сам объект момента не «привязан» к конкретной временной зоне — зона применяется только при отображении и преобразовании.

Ключевая особенность:

  • внутреннее значение всегда универсально (UTC)
  • отображение зависит от выбранной зоны
  • форматирование не изменяет сам момент, а лишь его представление
const m = moment();

Здесь создаётся момент в локальной зоне системы. При этом значение внутри объекта остаётся UTC-эквивалентом.


Подключение и использование moment-timezone

Для работы с временными зонами используется расширение:

moment.tz

Основной принцип — указание IANA-идентификатора зоны:

  • “Europe/Moscow”
  • “Asia/Almaty”
  • “America/New_York”

Пример создания момента в конкретной зоне:

const m = moment.tz("2026-05-21 12:00", "Asia/Almaty");

В этом случае строка интерпретируется как локальное время указанной зоны, а не системы.


Форматирование времени с указанием зоны

Форматирование выполняется методом format, однако зона влияет на результат только после её установки.

Базовое форматирование

const m = moment.tz("2026-05-21 12:00", "Asia/Almaty");

console.log(m.format("YYYY-MM-DD HH:mm"));

Вывод будет соответствовать времени в зоне Asia/Almaty.


Отображение смещения относительно UTC

Moment.js предоставляет несколько токенов для работы со смещениями:

  • Z — смещение в формате ±HH:mm
  • ZZ — смещение без двоеточия (±HHmm)
const m = moment.tz("2026-05-21 12:00", "Asia/Almaty");

console.log(m.format("YYYY-MM-DD HH:mm Z"));
console.log(m.format("YYYY-MM-DD HH:mm ZZ"));

Значение смещения

Смещение определяется относительно UTC и автоматически учитывает летнее/зимнее время, если оно применяется в выбранной зоне.


Явное преобразование между временными зонами

Одним из ключевых механизмов является метод tz для изменения представления времени без изменения базового момента.

const utcTime = moment.utc("2026-05-21 12:00");

const moscow = utcTime.clone().tz("Europe/Moscow");
const tokyo = utcTime.clone().tz("Asia/Tokyo");

Важно различать:

  • moment.utc() — фиксирует UTC-режим
  • .tz(zone) — переводит отображение в указанную зону

Разница между локальным временем и временной зоной

При отсутствии moment-timezone:

moment().format();

используется локальная зона окружения (операционной системы).

При использовании moment-timezone:

moment.tz("2026-05-21 12:00", "Europe/London");

временная зона становится частью логики интерпретации строки.


Форматирование с названием временной зоны

Moment.js позволяет выводить краткое обозначение зоны:

  • z — краткое имя зоны (например, GMT, EST)
  • ограниченная точность, зависит от конфигурации и данных IANA
const m = moment.tz("2026-05-21 12:00", "America/New_York");

console.log(m.format("YYYY-MM-DD HH:mm z"));

Следует учитывать, что z не всегда возвращает стабильное значение для всех зон.


Преобразование времени между зонами без потери исходного значения

При конвертации важно сохранять исходный момент:

const base = moment.tz("2026-05-21 12:00", "Asia/Almaty");

const ny = base.clone().tz("America/New_York");
const london = base.clone().tz("Europe/London");

Каждый вызов clone() предотвращает мутацию исходного объекта.


Работа с UTC как промежуточным форматом

UTC часто используется как универсальный слой между временными зонами.

const local = moment.tz("2026-05-21 12:00", "Asia/Almaty");

const utc = local.clone().utc();

console.log(utc.format("YYYY-MM-DD HH:mm"));

После перевода в UTC дальнейшее преобразование в любую зону становится предсказуемым.


Форматирование даты с учётом ISO и временной зоны

ISO-форматирование часто комбинируется с временными зонами:

const m = moment.tz("2026-05-21 12:00", "Asia/Almaty");

console.log(m.toISOString());

Метод toISOString всегда возвращает UTC, игнорируя текущую зону отображения.


Смещение и вычисления между зонами

Разница между временными зонами может быть вычислена через utcOffset:

const m = moment.tz("2026-05-21 12:00", "Asia/Almaty");

console.log(m.utcOffset());

Значение возвращается в минутах и позволяет выполнять арифметику времени:

const offsetHours = m.utcOffset() / 60;

Учет перехода на летнее время

Moment-timezone использует базу IANA, что позволяет автоматически учитывать DST:

const winter = moment.tz("2026-01-15 12:00", "Europe/Berlin");
const summer = moment.tz("2026-07-15 12:00", "Europe/Berlin");

console.log(winter.format("Z"));
console.log(summer.format("Z"));

Разные значения смещения отражают сезонные изменения.


Форматирование с фиксированными смещениями

Иногда требуется игнорировать правила временных зон и использовать фиксированный offset:

const m = moment().utcOffset("+03:00");

console.log(m.format("YYYY-MM-DD HH:mm Z"));

Такой подход не учитывает DST и используется в системах с фиксированным временем.


Сравнение временных зон через форматирование

Для визуального сравнения удобно выводить одинаковую дату в разных зонах:

const base = "2026-05-21 12:00";

const zones = ["Asia/Almaty", "Europe/Moscow", "America/New_York"];

zones.forEach(z => {
  console.log(moment.tz(base, z).format("YYYY-MM-DD HH:mm Z"));
});

Такой вывод позволяет увидеть реальную разницу во времени без дополнительных вычислений.


Особенности форматирования при цепочках преобразований

При последовательных вызовах важно учитывать порядок операций:

const m = moment.utc("2026-05-21 12:00")
  .tz("Asia/Almaty")
  .add(2, "hours")
  .format("YYYY-MM-DD HH:mm Z");

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


Использование локализации вместе с временными зонами

Форматирование может сочетаться с локалями:

moment.locale("ru");

const m = moment.tz("2026-05-21 12:00", "Europe/Moscow");

console.log(m.format("LLLL Z"));

Локаль влияет на текстовые элементы (названия месяцев, дней), но не изменяет вычисления зоны.


Особенности работы с историческими датами зон

Некоторые временные зоны изменяли свои правила в прошлом. IANA-база хранит такие изменения, поэтому результат форматирования зависит от года:

moment.tz("2010-05-21 12:00", "Europe/Moscow").format("Z");

Значение смещения для одной и той же зоны может отличаться в зависимости от исторического периода.


Практика комбинирования UTC, локального времени и зоны

Наиболее устойчивый подход к форматированию:

  1. хранение времени в UTC
  2. преобразование в нужную зону при выводе
  3. форматирование только после выбора зоны
const stored = moment.utc("2026-05-21 12:00");

const view = stored.clone()
  .tz("Asia/Almaty")
  .format("YYYY-MM-DD HH:mm Z");