Работа с календарями в JavaScript часто сводится к необходимости учитывать не только момент времени, но и способ его представления: локаль, систему летоисчисления, начало недели, формат календаря и правила отображения дат в разных регионах. Luxon предоставляет слой абстракции над стандартным объектом Date, позволяя управлять календарными представлениями без ручной нормализации и сложных преобразований.
В основе Luxon лежит представление времени в виде неизменяемого
объекта DateTime. Он хранит:
Важно различать два уровня:
Одна и та же дата может выглядеть по-разному в зависимости от локали или календарной системы.
Одним из ключевых механизмов работы с календарями является параметр
outputCalendar. Он влияет только на отображение даты, не
меняя её абсолютного значения.
Пример:
import { DateTime } from "luxon";
const dt = DateTime.now();
dt.setLocale("en").toString();
dt.setLocale("ar").toString();
Более точное управление осуществляется через
outputCalendar:
const dt = DateTime.now().set({
outputCalendar: "gregory"
});
Поддерживаемые календарные системы:
gregory — григорианский календарь (по умолчанию)buddhist — буддийскийislamic — исламский (Hijri)hebrew — еврейскийindian — индийский национальный календарьchinese — китайский календарьПереключение календаря не изменяет момент времени, а изменяет отображение года, месяца и дня.
Календарь тесно связан с локалью. Локаль влияет на:
Пример:
const dt = DateTime.now().setLocale("fr");
В французской локали неделя может начинаться с понедельника, тогда как в американской — с воскресенья.
Luxon опирается на Intl API, поэтому поведение
соответствует стандартам Unicode CLDR.
В календарных системах особое значение имеет понятие недели. Luxon позволяет управлять этим через локаль и методы форматирования.
Основные аспекты:
Пример получения номера недели:
const dt = DateTime.local(2026, 1, 15);
dt.weekNumber;
dt.weekYear;
ISO-неделя используется по умолчанию в большинстве сценариев серверной логики.
Luxon разделяет хранение данных и их отображение. Один и тот же объект можно представить по-разному:
const dt = DateTime.local(2026, 5, 23);
dt.toISO();
dt.toLocaleString();
dt.toFormat("dd LLLL yyyy");
Календарные особенности проявляются особенно ярко при использовании нестандартных систем летоисчисления:
const dt = DateTime.now().set({
outputCalendar: "islamic"
});
dt.toLocaleString(DateTime.DATE_FULL);
В этом случае год и месяц интерпретируются в соответствии с исламским календарём, хотя внутреннее значение остаётся Unix-based.
Хотя Luxon не предоставляет встроенный scheduler, календарная модель
позволяет строить расписания через Interval и
Duration.
import { DateTime, Interval } from "luxon";
const start = DateTime.local(2026, 5, 1);
const end = DateTime.local(2026, 5, 31);
const interval = Interval.fromDateTimes(start, end);
Интервалы позволяют:
interval.contains(DateTime.local(2026, 5, 10));
Типичная задача календарных приложений — генерация сетки месяца.
Алгоритм:
Пример:
const start = DateTime.local(2026, 5, 1);
const firstWeek = start.startOf("week");
const days = Array.from({ length: 42 }, (_, i) =>
firstWeek.plus({ days: i })
);
Такая структура учитывает:
Календарные расчёты часто опираются на нормализацию дат:
const dt = DateTime.local(2026, 5, 23);
dt.startOf("day");
dt.endOf("month");
dt.startOf("week");
Поддерживаемые уровни:
Эти операции критичны при построении расписаний и агрегации событий.
Календарь невозможно отделить от временной зоны. Один и тот же календарный день может начинаться в разные моменты UTC.
const dt = DateTime.local().setZone("Europe/Paris");
Особенности:
При переходе через DST (летнее время) календарные сутки могут содержать 23 или 25 часов, что влияет на расчёт расписаний.
При проектировании расписаний важно различать:
Рекомендуемый подход:
startOfПример:
const events = [
DateTime.fromISO("2026-05-23T10:00:00Z"),
DateTime.fromISO("2026-05-23T15:00:00Z")
];
const grouped = events.reduce((acc, dt) => {
const key = dt.startOf("day").toISODate();
acc[key] = (acc[key] || 0) + 1;
return acc;
}, {});
При проектировании расписаний важно учитывать:
Luxon позволяет переключать календарное представление, но бизнес-логика обычно требует дополнительного слоя данных поверх календаря.
Пример сценария:
startOf("day")startOf("week")Luxon не содержит встроенного cron-планировщика, но календарная модель позволяет строить повторения вручную:
const base = DateTime.local(2026, 5, 1);
const series = Array.from({ length: 10 }, (_, i) =>
base.plus({ weeks: i })
);
Для более сложных случаев:
plus({ months: 1 })plus({ years: 1 })Важный аспект — корректное вычисление границ:
const monthStart = DateTime.local(2026, 5, 23).startOf("month");
const monthEnd = DateTime.local(2026, 5, 23).endOf("month");
Использование таких границ критично при:
Локаль влияет не только на язык, но и на восприятие расписания:
DateTime.local().setLocale("en-GB").toLocaleString();
DateTime.local().setLocale("en-US").toLocaleString();
Разница в календарном представлении может быть значимой при работе с международными системами планирования.
При построении календарных интерфейсов используются следующие принципы:
startOf("week")startOf("month")plus({ days: 1 })Такой подход обеспечивает стабильность при смене локали и временной
зоны, так как календарные вычисления базируются на
DateTime, а не на сырых timestamp-значениях.