В библиотеке js-joda работа с часовыми поясами построена вокруг
неизменяемых объектов ZoneId и набора правил
ZoneRules. Архитектура сознательно повторяет подход Java
Time API, где ключевой оптимизацией выступает переиспользование уже
созданных экземпляров зон и их правил вместо повторного построения.
ZoneId представляет собой идентификатор часового пояса
(например, Europe/Moscow или Asia/Almaty). Сам
по себе объект не хранит сложную логику, а выступает ссылкой на набор
правил.
ZoneId ZoneRules
ZoneRules содержит детальное описание поведения
зоны:
Именно ZoneRules является наиболее «тяжёлой» частью
модели, поскольку включает в себя набор интервалов и переходов, которые
могут покрывать десятки лет истории.
В js-joda идентификаторы зон создаются через фабричный метод:
import { ZoneId } from '@js-joda/core';
const zone = ZoneId.of('Europe/Moscow');
Повторные вызовы ZoneId.of('Europe/Moscow') не обязаны
создавать новый объект. Внутри используется кеширование идентификаторов,
чтобы:
Поведение можно описать как ленивое хранение:
первый вызов → парсинг строки → создание ZoneId → запись в кеш
последующие вызовы → возврат из кеша
Это критично для сценариев, где работа с датами происходит в циклах или при обработке потоков событий.
Основная нагрузка приходится на ZoneRules. При первом
обращении к зоне библиотека загружает и вычисляет набор правил, после
чего они сохраняются.
Кешируются:
При повторном использовании той же зоны:
const z = ZoneId.of('Asia/Almaty');
const rules = z.rules();
rules() возвращает уже готовый объект без повторной
загрузки данных.
Важная особенность: кешируется не только сам объект правил, но и результаты вычислений для конкретных временных точек.
В чистом @js-joda/core отсутствуют данные о реальных
часовых поясах. Для работы с ними используется пакет расширения:
@js-joda/timezoneОн содержит предсобранные TZDB-данные (IANA Time Zone Database), которые:
ZoneRulesProvider;После загрузки библиотека работает исключительно с уже подготовленными структурами, избегая чтения и парсинга исходных данных.
При создании объектов ZonedDateTime кеширование
проявляется косвенно через повторное использование зон:
import { ZonedDateTime, ZoneId, LocalDateTime } from '@js-joda/core';
const zone = ZoneId.of('Europe/Moscow');
const zdt1 = ZonedDateTime.of(LocalDateTime.now(), zone);
const zdt2 = ZonedDateTime.of(LocalDateTime.now(), zone);
Обе операции используют один и тот же экземпляр ZoneId,
а значит:
Основная стоимость остаётся в вычислении LocalDateTime,
а не в работе с зоной.
В высоконагруженных приложениях повторный парсинг строковых идентификаторов становится узким местом. Поэтому применяется явное кеширование на уровне приложения:
const ZONES = Object.freeze({
MOSCOW: ZoneId.of('Europe/Moscow'),
ALMATY: ZoneId.of('Asia/Almaty'),
LONDON: ZoneId.of('Europe/London')
});
Такой подход даёт несколько эффектов:
ZoneId.of;В динамических сценариях, где зоны приходят извне, применяется мемоизация:
const zoneCache = new Map();
function getZone(id) {
if (!zoneCache.has(id)) {
zoneCache.set(id, ZoneId.of(id));
}
return zoneCache.get(id);
}
Это особенно важно при обработке:
Наиболее сложная часть — обработка переходов летнего времени. Для каждой зоны существует набор правил, который может изменяться во времени.
ZoneRules кеширует уже рассчитанные переходы, чтобы
избежать повторных вычислений:
Это позволяет быстро вычислять смещение для любой даты:
const zone = ZoneId.of('Europe/Berlin');
const rules = zone.rules();
rules.offset(Instant.now());
Каждый вызов использует уже подготовленные интервалы.
Кеширование зон и правил увеличивает потребление памяти, но снижает вычислительную стоимость операций с датами. В типичных приложениях баланс смещён в сторону кеширования, поскольку:
Таким образом, модель js-joda ориентирована на долгоживущие кеши и минимизацию повторной работы с временными зонами.