Календарная система

Библиотека Luxon строится вокруг объекта DateTime, который по умолчанию использует григорианский календарь, но при этом поддерживает работу с альтернативными календарными системами через механизм локализации и параметр outputCalendar.

Календарная система в Luxon определяет не только формат отображения даты, но и сам способ интерпретации года, месяца и дня в различных культурных и религиозных традициях. Внутри библиотека опирается на возможности Intl API, поэтому поддержка календарей зависит от окружения выполнения.


Базовый календарь: ISO / Gregorian

Любая дата, созданная стандартными методами Luxon, интерпретируется в ISO-8601 представлении, которое фактически эквивалентно григорианскому календарю.

import { DateTime } from "luxon";

const dt = DateTime.now();

console.log(dt.toISO());

Внутренне это всегда:

  • год в григорианской системе
  • месяц от 1 до 12
  • день месяца от 1 до 31
  • неделя начинается с понедельника (ISO-неделя)

Григорианский календарь является базовым, и все вычисления (plus, minus, startOf, endOf) выполняются именно в его логике, независимо от того, как дата будет отображена.


Понятие outputCalendar

Ключевой механизм работы с календарными системами в Luxon — параметр:

outputCalendar

Он определяет, в каком календаре будет отображаться дата, но не изменяет внутреннее хранение.

Пример использования

const dt = DateTime.now().setLocale("en");

console.log(dt.set({ outputCalendar: "buddhist" }).toString());

Возможный результат будет отличаться только визуально, например год может быть смещён (в буддийском календаре он обычно на +543 года относительно григорианского).


Поддерживаемые календарные системы

Luxon опирается на Intl.DateTimeFormat, поэтому список доступных календарей фиксирован и зависит от ICU:

  • gregory — григорианский календарь (по умолчанию)
  • buddhist — буддийский календарь
  • chinese — китайский лунно-солнечный календарь
  • islamic — исламский календарь (хиджра)
  • hebrew — еврейский календарь
  • indian — индийский национальный календарь
  • japanese — японские эры (Reiwa, Heisei и т.д.)

Установка календаря через set

Наиболее прямой способ изменить календарную систему — указать outputCalendar при форматировании или через set.

const dt = DateTime.local(2026, 5, 23);

const hebrew = dt.set({ outputCalendar: "hebrew" });
const islamic = dt.set({ outputCalendar: "islamic" });

console.log(hebrew.toString());
console.log(islamic.toString());

Важно: сам объект DateTime остаётся неизменяемым. Каждый вызов set создаёт новый экземпляр.


Форматирование с учётом календаря

Календарная система проявляется в форматировании строк:

const dt = DateTime.local(2026, 5, 23);

console.log(dt.set({ outputCalendar: "gregory" }).toLocaleString(DateTime.DATE_FULL));
console.log(dt.set({ outputCalendar: "buddhist" }).toLocaleString(DateTime.DATE_FULL));

Разница будет в представлении года и иногда названия месяца, в зависимости от локали.


Поведение арифметики дат

Ключевой принцип Luxon:

Календарная система влияет только на отображение, но не на математические операции.

const dt = DateTime.local(2026, 5, 23);

const nextWeek = dt.plus({ days: 7 });

console.log(nextWeek.set({ outputCalendar: "islamic" }).toISO());

Здесь:

  • plus({ days: 7 }) всегда добавляет 7 дней в ISO-календаре
  • outputCalendar лишь меняет интерпретацию результата

Влияние локали на календарь

Календарь тесно связан с локалью:

const dt = DateTime.local(2026, 5, 23);

console.log(dt.setLocale("ja").set({ outputCalendar: "japanese" }).toString());

Японский календарь использует эры, например:

  • Reiwa 8 (вместо 2026)
  • Heisei, Showa и др.

Luxon не вычисляет эти эры вручную — они предоставляются системой Intl.


Ограничения календарных систем

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

1. Нет преобразования между календарями как независимых сущностей

Luxon не хранит дату как “объект календаря”. Внутреннее представление всегда ISO.

2. Арифметика не календарно-зависимая

dt.plus({ months: 1 })

всегда означает календарное смещение в григорианской системе.

3. Зависимость от окружения

Некоторые календари могут быть недоступны в старых средах выполнения JavaScript.


Работа с китайским календарём

Китайский календарь особенно интересен, так как он лунно-солнечный:

const dt = DateTime.local(2026, 5, 23);

console.log(dt.set({ outputCalendar: "chinese" }).toLocaleString(DateTime.DATE_FULL));

Особенности:

  • месяцы могут не совпадать с григорианскими
  • возможны дополнительные месяцы (вставочные)
  • отображение зависит от ICU данных

Исламский календарь

Исламский календарь (islamic) является лунным и короче григорианского примерно на 11 дней в год:

const dt = DateTime.local(2026, 5, 23);

const islamic = dt.set({ outputCalendar: "islamic" });

console.log(islamic.toLocaleString(DateTime.DATE_FULL));

Характеристики:

  • годы меньше по значению
  • месяцы полностью лунные
  • смещение относительно григорианского постоянно меняется

Еврейский календарь

const dt = DateTime.local(2026, 5, 23);

console.log(dt.set({ outputCalendar: "hebrew" }).toLocaleString(DateTime.DATE_FULL));

Особенности:

  • сочетает лунные и солнечные циклы
  • может иметь високосные месяцы
  • год начинается осенью (Тишрей)

Японский календарь и эры

const dt = DateTime.local(2026, 5, 23);

console.log(dt.set({ outputCalendar: "japanese" }).toLocaleString(DateTime.DATE_FULL));

Система основана на императорских эрах:

  • Reiwa (2019–)
  • Heisei (1989–2019)
  • Showa (1926–1989)

Luxon отображает дату через механизм ICU, который вычисляет текущую эру автоматически.


Индийский календарь

const dt = DateTime.local(2026, 5, 23);

console.log(dt.set({ outputCalendar: "indian" }).toLocaleString(DateTime.DATE_FULL));

Используется в официальных документах Индии:

  • синхронизирован с григорианским календарём
  • месяцы имеют локальные названия
  • отличается системой нумерации лет

Комбинация календаря и зоны времени

Календарная система часто используется вместе с часовыми поясами:

const dt = DateTime.now().setZone("Asia/Almaty");

const formatted = dt.set({ outputCalendar: "islamic" }).toString();

console.log(formatted);

Здесь:

  • setZone управляет временем
  • outputCalendar управляет представлением даты

Влияние календаря на парсинг и сериализацию

При преобразовании в строки:

const dt = DateTime.local(2026, 5, 23);

const json = dt.set({ outputCalendar: "hebrew" }).toJSON();

важно понимать:

  • JSON всегда возвращает ISO-представление
  • outputCalendar не сохраняется в сериализации
  • при восстановлении календарь нужно задавать заново

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

Международные приложения

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

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

  • отчёты по локальным календарям
  • соответствие государственным стандартам

Образовательные платформы

  • сравнение календарных систем
  • изучение культурных различий в измерении времени

Особенности поведения DateTime при смене календаря

При переключении outputCalendar:

  • epoch (timestamp) остаётся неизменным
  • вычисления не пересчитываются
  • изменяется только слой отображения
const dt = DateTime.local(2026, 5, 23);

const a = dt.set({ outputCalendar: "gregory" });
const b = dt.set({ outputCalendar: "buddhist" });

console.log(a.ts === b.ts); // true

Это ключевая гарантия неизменности временной точки независимо от календаря.