В библиотеке js-joda вся работа с временем опирается на строгую модель разделения между моментом времени и его представлением в конкретной временной зоне. UTC (Coordinated Universal Time) выступает как базовая система отсчёта, в которой любой момент выражается независимо от географического положения и правил перехода на летнее время.
Ключевая идея: UTC в js-joda — это не формат отображения, а
фундаментальная ось времени, представленная типом
Instant.
Instant представляет собой точку на временной шкале UTC
с точностью до наносекундной части (в рамках возможностей JavaScript —
до миллисекунд).
Он не содержит информации о временной зоне, смещении или локализации.
import { Instant } from '@js-joda/core';
const now = Instant.now();
Instant.now() всегда возвращает текущее время в
UTC-координате, независимо от локальной системы.
const instant = Instant.parse('2026-05-24T12:30:00Z');
Суффикс Z означает UTC (Zulu time). Это строгий
индикатор нулевого смещения.
instant.toEpochMilli();
Возвращает количество миллисекунд с 1970-01-01T00:00:00Z.
Instant.ofEpochSecond(0);
Создаёт момент из UNIX timestamp.
В js-joda различаются два концептуально связанных, но разных объекта:
ZoneOffset.UTC — фиксированное смещение +00:00ZoneId.UTC — идентификатор временной зоны UTCИспользуется, когда важно фиксированное смещение без правил календаря:
import { ZoneOffset } from '@js-joda/core';
const offset = ZoneOffset.UTC;
Используется в контексте ZonedDateTime:
import { ZoneId } from '@js-joda/core';
const zone = ZoneId.UTC;
Разница становится критичной при работе с API, где требуется либо абстрактная зона, либо конкретное смещение.
Основная операция при работе с UTC — нормализация локального времени в момент.
import { ZonedDateTime, ZoneId } from '@js-joda/core';
const zdt = ZonedDateTime.now(ZoneId.systemDefault());
const instant = zdt.toInstant();
toInstant() полностью убирает информацию о зоне и
возвращает абсолютный момент.
Обратная операция требует привязки к временной зоне.
const utcInstant = Instant.now();
const localZdt = utcInstant.atZone(ZoneId.systemDefault());
Тот же момент времени интерпретируется в локальной зоне пользователя.
OffsetDateTime хранит дату и время вместе со смещением
от UTC, но без полной зоны.
import { OffsetDateTime, ZoneOffset, Instant } from '@js-joda/core';
const instant = Instant.now();
const utcDateTime = instant.atOffset(ZoneOffset.UTC);
Такой объект фиксирует смещение +00:00, но не содержит
правил перехода времени.
При использовании ZonedDateTime с UTC поведение
становится полностью детерминированным.
import { ZonedDateTime, ZoneId } from '@js-joda/core';
const utcZdt = ZonedDateTime.now(ZoneId.UTC);
В этом случае:
Instant, но с дополнительной
структурой даты и времениСтандартное представление UTC в ISO-8601:
YYYY-MM-DDTHH:mm:ssZ
В js-joda форматирование выполняется через
DateTimeFormatter.
import { Instant, DateTimeFormatter } from '@js-joda/core';
const instant = Instant.parse('2026-05-24T10:15:30Z');
const formatted = instant.toString();
Instant.toString() всегда возвращает строку с
Z.
import { ZonedDateTime, ZoneId, DateTimeFormatter } from '@js-joda/core';
const zdt = ZonedDateTime.now(ZoneId.UTC);
const formatter = DateTimeFormatter.ISO_INSTANT;
const result = formatter.format(zdt);
ISO_INSTANT гарантирует вывод в UTC-нормализации.
Операции сложения и вычитания времени в UTC всегда выполняются без влияния временных зон.
import { Instant, Duration } from '@js-joda/core';
const start = Instant.parse('2026-05-24T00:00:00Z');
const end = start.plus(Duration.ofHours(5));
Результат всегда остаётся в UTC-координате.
const diff = end.minusSeconds(3600);
Все операции выполняются линейно по временной шкале.
Одним из наиболее стабильных способов работы с UTC является использование epoch-значений.
const instant = Instant.now();
const millis = instant.toEpochMilli();
const restored = Instant.ofEpochMilli(millis);
Этот подход исключает любые неоднозначности, связанные с зонами или календарями.
Часто требуется сравнение локального времени и UTC-представления одного и того же момента.
import { Instant, ZoneId } from '@js-joda/core';
const instant = Instant.now();
const systemZdt = instant.atZone(ZoneId.systemDefault());
const utcZdt = instant.atZone(ZoneId.UTC);
Оба объекта указывают на один и тот же момент, но имеют разное отображение календарных полей.
UTC полностью исключает проблему перехода на летнее время.
При использовании:
ZoneId.UTC
или
ZoneOffset.UTC
любые правила DST игнорируются.
Это делает UTC предпочтительным форматом для:
Часто входные строки содержат либо явный UTC, либо локальное время без зоны.
const instant = Instant.parse('2026-05-24T18:00:00Z');
import { LocalDateTime, ZoneId } from '@js-joda/core';
const ldt = LocalDateTime.parse('2026-05-24T18:00:00');
const instant = ldt.atZone(ZoneId.systemDefault()).toInstant();
Этот шаг критичен для устранения неоднозначностей при интерпретации данных.
Все сравнения Instant выполняются как числовые сравнения
на временной шкале UTC.
const a = Instant.parse('2026-05-24T10:00:00Z');
const b = Instant.parse('2026-05-24T12:00:00Z');
const isBefore = a.isBefore(b);
const zdt = ZonedDateTime.now(ZoneId.systemDefault());
const wrong = zdt.toLocalDateTime(); // теряется информация о моменте
LocalDateTime не содержит UTC-координаты, что делает его
непригодным для хранения абсолютного времени.
const instant1 = Instant.parse('2026-05-24T10:00:00Z');
const instant2 = Instant.parse('2026-05-24T10:00:00+00:00');
Обе строки эквивалентны, но различия в источниках данных могут приводить к ошибкам при агрегации.
const zdt = ZonedDateTime.now(ZoneId.systemDefault());
Без последующего преобразования в Instant такие значения
нельзя безопасно передавать между системами.
Во всех сценариях обмена данными применяется единая схема:
ZonedDateTime или
LocalDateTimetoInstant()InstantatZone(ZoneId...)const instant = ZonedDateTime.now(ZoneId.systemDefault()).toInstant();
const back = instant.atZone(ZoneId.UTC);
Эта модель исключает неоднозначность временных интерпретаций и делает UTC единственным источником истины для временных вычислений.