ZonedDateTime представляет собой один из ключевых типов в js-joda, предназначенный для работы с моментами времени с учётом часового пояса и правил смещения (UTC offset). В отличие от локальных представлений даты и времени, данный тип фиксирует не только календарно-временную структуру, но и контекст зоны, что делает его основным инструментом для серверных приложений, распределённых систем и любых сценариев, где критична точность временных меток.
ZonedDateTime объединяет три сущности:
Такое объединение позволяет однозначно определить момент времени на временной шкале UTC и одновременно сохранить его локальное представление.
Ключевая особенность: ZonedDateTime всегда привязан к конкретной зоне, а не просто к фиксированному смещению. Это означает, что он учитывает исторические изменения правил часовых поясов, включая переходы на летнее/зимнее время.
import { ZonedDateTime, ZoneId } from '@js-joda/core';
const now = ZonedDateTime.now(ZoneId.of('Europe/Berlin'));
Если зона не указана, используется системная:
const systemNow = ZonedDateTime.now();
Instant — это абсолютная точка на временной оси UTC.
import { Instant, ZonedDateTime, ZoneId } from '@js-joda/core';
const instant = Instant.now();
const zdt = ZonedDateTime.ofInstant(instant, ZoneId.of('Asia/Almaty'));
Этот способ используется при конвертации серверных timestamp в локальные представления.
import { LocalDateTime, ZonedDateTime, ZoneId } from '@js-joda/core';
const ldt = LocalDateTime.of(2026, 5, 24, 10, 30);
const zdt = ZonedDateTime.of(ldt, ZoneId.of('America/New_York'));
Здесь важно понимать: один и тот же LocalDateTime может соответствовать разным моментам времени в зависимости от зоны.
ZonedDateTime можно рассматривать как комбинацию:
const zone = zdt.zone();
const offset = zdt.offset();
const local = zdt.toLocalDateTime();
import { ZoneId } from '@js-joda/core';
const zone = ZoneId.of('Europe/Moscow');
Список зон основан на базе IANA (tz database), что обеспечивает корректную работу исторических переходов.
const original = ZonedDateTime.now(ZoneId.of('Asia/Tokyo'));
const converted = original.withZoneSameInstant(ZoneId.of('Europe/Paris'));
Метод withZoneSameInstant сохраняет абсолютный момент времени, меняя только представление.
const shifted = original.withZoneSameLocal(ZoneId.of('Europe/Paris'));
Этот вариант интерпретирует локальное время в новой зоне, что может привести к изменению фактического момента времени.
Одна из сложностей ZonedDateTime — переходы между зимним и летним временем.
При создании времени в период перехода возможны:
Пример:
const zdt = ZonedDateTime.of(
LocalDateTime.of(2026, 3, 29, 2, 30),
ZoneId.of('Europe/Berlin')
);
Такое время может не существовать из-за перехода DST. Библиотека применяет правила зоны и корректирует значение.
ZonedDateTime поддерживает операции смещения:
const future = zdt.plusHours(5);
const nextDay = zdt.plusDays(1);
const past = zdt.minusMinutes(90);
Важно: операции учитывают переходы часовых поясов. Добавление 24 часов не всегда эквивалентно «следующему календарному дню» в локальной зоне.
const a = ZonedDateTime.now(ZoneId.of('UTC'));
const b = ZonedDateTime.now(ZoneId.of('Europe/London'));
const result = a.isBefore(b);
Сравнение выполняется по абсолютному моменту времени, а не по локальному представлению.
const duration = a.until(b);
const seconds = duration.seconds();
Результат всегда выражается относительно UTC-оси.
const str = zdt.toString();
Формат ISO-8601 с зоной:
2026-05-24T10:30+03:00[Asia/Almaty]
import { ZonedDateTime } from '@js-joda/core';
const parsed = ZonedDateTime.parse(
'2026-05-24T10:30+03:00[Asia/Almaty]'
);
Парсер требует корректного указания зоны.
ZonedDateTime часто используется как промежуточное представление:
const instant = zdt.toInstant();
Instant используется для хранения в базе данных, логирования и передачи по API.
const restored = ZonedDateTime.ofInstant(
instant,
ZoneId.of('Europe/Paris')
);
Один и тот же Instant может выглядеть по-разному в разных зонах.
ZonedDateTime позволяет фиксировать событие с учётом локальной зоны пользователя:
const eventTime = ZonedDateTime.now(userZone);
const scheduled = ZonedDateTime.of(
2026, 6, 1, 9, 0, 0, 0,
ZoneId.of('Asia/Almaty')
);
В логах предпочтительно использовать Instant, но ZonedDateTime помогает восстановить контекст:
const logTime = ZonedDateTime.now(ZoneId.of('UTC'));
ZonedDateTime является immutable:
const updated = zdt.plusDays(1);
// zdt остаётся прежним
Это свойство упрощает работу в многопоточных и асинхронных средах.
При сохранении рекомендуется:
const dbValue = zdt.toInstant().toString();
При восстановлении — явное указание зоны:
const zdtFromDb = ZonedDateTime.ofInstant(
Instant.parse(dbValue),
ZoneId.of('Asia/Almaty')
);
Использование LocalDateTime вместо ZonedDateTime приводит к неоднозначности времени.
ZoneId содержит правила, OffsetDateTime — только фиксированное смещение. ZonedDateTime учитывает оба уровня.
Частая ошибка — использовать withZoneSameLocal вместо withZoneSameInstant, что приводит к смещению момента времени.
ZonedDateTime более тяжёлый по сравнению с LocalDateTime и Instant из-за:
Поэтому в высоконагруженных системах:
ZonedDateTime можно рассматривать как наиболее полную форму представления времени в экосистеме даты и времени библиотеки.