DateTime, Duration, Interval

DateTime в Luxon представляет собой неизменяемую (immutable) модель конкретного момента времени с привязкой к часовому поясу, календарной системе и локали. В отличие от стандартного Date в JavaScript, DateTime не смешивает представление времени и его внутреннюю структуру, что делает операции преобразования и форматирования предсказуемыми.

Создание DateTime

Основной способ создания — через статические методы:

import { DateTime } from "luxon";

const now = DateTime.now();

const fromObject = DateTime.fromObject({
  year: 2026,
  month: 5,
  day: 24,
  hour: 14,
  minute: 30
});

const fromISO = DateTime.fromISO("2026-05-24T14:30:00");

const fromMillis = DateTime.fromMillis(1716556200000);

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

Часовые пояса и локали

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

const utcTime = DateTime.now().toUTC();

const tokyoTime = DateTime.now().setZone("Asia/Tokyo");

const parisTime = DateTime.now().setZone("Europe/Paris");

Установка локали влияет на форматирование:

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

dt.toLocaleString(DateTime.DATE_FULL);

Форматирование

Luxon предоставляет несколько уровней форматирования:

const dt = DateTime.now();

dt.toISO();
dt.toISODate();
dt.toISOTime();

dt.toFormat("dd.MM.yyyy HH:mm");
dt.toLocaleString(DateTime.DATETIME_MED);

Кастомные форматы используют токены:

  • yyyy — год
  • MM — месяц
  • dd — день
  • HH — часы (24-часовой формат)
  • mm — минуты

Арифметика DateTime

Все операции возвращают новый объект:

const dt = DateTime.now();

const future = dt.plus({ days: 5, hours: 2 });
const past = dt.minus({ months: 1 });

Поддерживаются единицы:

  • years
  • months
  • weeks
  • days
  • hours
  • minutes
  • seconds
  • milliseconds

Сравнение

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

const a = DateTime.fromISO("2026-01-01");
const b = DateTime.fromISO("2026-02-01");

a < b;
a.equals(b);
a.toMillis() === b.toMillis();

Для упорядочивания:

const sorted = [a, b].sort((x, y) => x - y);

Duration

Duration представляет промежуток времени, независимый от конкретной точки отсчёта. Это абстракция длины времени, а не момента.

Создание Duration

import { Duration } from "luxon";

const d1 = Duration.fromObject({
  hours: 2,
  minutes: 30
});

const d2 = Duration.fromMillis(9000000);

Также возможно создание из ISO 8601:

const d = Duration.fromISO("PT2H30M");

Нормализация

Duration может автоматически приводить значения к удобному виду:

const d = Duration.fromObject({ minutes: 150 });

d.shiftTo("hours", "minutes").toObject();

Результат:

{ hours: 2, minutes: 30 }

Арифметика Duration

const a = Duration.fromObject({ hours: 1 });
const b = Duration.fromObject({ minutes: 30 });

const sum = a.plus(b);
const diff = a.minus(b);

Применение к DateTime

Duration часто используется вместе с DateTime:

const dt = DateTime.now();

const result = dt.plus(Duration.fromObject({ days: 3 }));

Представления

const d = Duration.fromObject({ hours: 1, minutes: 15 });

d.as("minutes"); // 75
d.toISO();       // PT1H15M
d.toObject();    // { hours: 1, minutes: 15 }

Interval

Interval представляет непрерывный диапазон между двумя DateTime. Это структура для работы с временными промежутками, пересечениями и проверками включения.

Создание Interval

import { Interval, DateTime } from "luxon";

const start = DateTime.fromISO("2026-01-01");
const end = DateTime.fromISO("2026-01-10");

const interval = Interval.fromDateTimes(start, end);

Также возможно создание из объекта:

const interval = Interval.after(start, { days: 7 });

Или до момента:

const interval = Interval.before(end, { days: 7 });

Проверка включения

const dt = DateTime.fromISO("2026-01-05");

interval.contains(dt);

Метод возвращает true, если момент находится внутри диапазона.

Пересечения интервалов

const i1 = Interval.fromDateTimes(
  DateTime.fromISO("2026-01-01"),
  DateTime.fromISO("2026-01-10")
);

const i2 = Interval.fromDateTimes(
  DateTime.fromISO("2026-01-05"),
  DateTime.fromISO("2026-01-15")
);

const overlap = i1.overlaps(i2);
const intersection = i1.intersection(i2);

intersection возвращает новый Interval или null, если пересечения нет.

Объединение интервалов

const merged = i1.union(i2);

Объединение возможно только при пересечении или смежности.

Разбиение интервала

const parts = i1.splitAt(DateTime.fromISO("2026-01-05"));

Результат — массив интервалов.

Итерация по интервалу

Интервал можно разбивать на шаги:

const hourly = interval.splitBy({ hours: 1 });

Это создаёт массив интервалов фиксированной длительности.

Длительность интервала

interval.toDuration(["days", "hours"]);

Позволяет получить Duration, описывающий длину интервала.

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

interval.isValid;

Невалидный интервал возникает при ошибках в границах (например, end < start).


Взаимодействие DateTime, Duration и Interval

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

DateTime задаёт точку на оси времени, Duration определяет расстояние между точками, Interval описывает диапазон.

const start = DateTime.now();
const duration = Duration.fromObject({ days: 10 });

const end = start.plus(duration);
const interval = Interval.fromDateTimes(start, end);

Операции изменения времени не модифицируют исходные объекты:

const shifted = start.plus({ hours: 5 });

start === shifted; // false

Interval может использовать Duration для анализа длины:

interval.toDuration(["days"]).days;

Такое разделение ответственности позволяет строить предсказуемые вычисления времени без скрытых побочных эффектов.