Неизменяемость объектов

Библиотека Luxon построена вокруг принципа иммутабельности (immutability), при котором объекты даты и времени не изменяются после создания. Любая операция над временем приводит не к модификации существующего объекта, а к созданию нового экземпляра с изменёнными данными.

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


Основной принцип неизменяемости

В основе модели Luxon лежит простое правило:

любой метод, который «меняет» дату или время, возвращает новый объект

Это означает:

  • исходный объект остаётся неизменным;
  • результат операции существует отдельно;
  • цепочки операций безопасны и предсказуемы.

Пример концептуального поведения:

const dt1 = DateTime.local(2024, 1, 1);
const dt2 = dt1.plus({ days: 5 });

console.log(dt1.toISO()); // 2024-01-01...
console.log(dt2.toISO()); // 2024-01-06...

dt1 не изменился, хотя была выполнена операция добавления дней.


DateTime как неизменяемый объект

Ключевая сущность Luxon — DateTime — полностью иммутабельна. Это касается всех аспектов:

  • даты и времени;
  • часового пояса;
  • локали;
  • формата представления;
  • внутренних настроек календаря.

Любое изменение состояния создаёт новый объект:

const dt = DateTime.local(2024, 5, 10);

const upd ated = dt.se t({ hour: 15 });

console.log(dt.hour);       // исходное значение
console.log(upd ated.hour);  // 15

Метод set() не модифицирует объект, несмотря на семантику «установки».


Операции, возвращающие новые объекты

Арифметика времени

Методы plus и minus создают новые экземпляры:

const base = DateTime.local(2024, 6, 1);

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

Каждый результат — отдельный DateTime.


Изменение отдельных полей

Метод set работает аналогично функциональному обновлению состояния:

const dt = DateTime.local(2024, 7, 20);

const modified = dt.se t({
  year: 2025,
  minute: 30
});

Даже частичное изменение создаёт новый объект с полной копией всех остальных полей.


Работа с часовыми поясами

Смена временной зоны также не изменяет исходный объект:

const utcTime = DateTime.utc(2024, 1, 1, 12);

const localTime = utcTime.setZone('Europe/Berlin');

utcTime остаётся в UTC, а localTime — новый объект с пересчитанным временем.


Duration и неизменяемые интервалы

Duration также следует принципу иммутабельности.

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

Любая арифметика с длительностями создаёт новый объект.

Это критично для:

  • расчётов расписаний;
  • таймеров;
  • накопительных интервалов.

Settings и конфигурации

Глобальные настройки Luxon также отделены от состояния объектов.

Settings.defaultLocale = 'ru';
Settings.defaultZone = 'UTC';

Однако даже при изменении глобальных параметров уже созданные объекты DateTime не пересчитываются автоматически. Их внутреннее состояние фиксировано в момент создания.


Причины выбора иммутабельной модели

Предсказуемость

Иммутабельность устраняет класс ошибок, связанных с неожиданным изменением данных:

  • объект нельзя изменить «в другом месте кода»;
  • результат операции всегда детерминирован.

Безопасность в цепочках вызовов

Цепочки операций становятся безопасными:

const result = DateTime.local()
  .plus({ days: 1 })
  .set({ hour: 9 })
  .setZone('Europe/London');

Каждый шаг создаёт новый объект, не влияя на предыдущие.


Отсутствие скрытых побочных эффектов

В отличие от Date, где:

const d = new Date();
d.setDate(d.getDate() + 1);

переменная изменяется напрямую, Luxon полностью исключает подобные сценарии.


Сравнение с изменяемым Date

Классический Date в Jav * aScript:

  • изменяет внутреннее состояние;
  • требует осторожности при передаче по ссылке;
  • легко приводит к ошибкам в больших системах.

Luxon:

  • создаёт новые экземпляры;
  • не допускает случайной мутации;
  • упрощает reasoning о коде.

Копирование и «изменение» объектов

Поскольку изменение невозможно, «обновление» всегда сводится к созданию нового экземпляра на основе старого:

const original = DateTime.local(2024, 3, 15);

const upd ated = original.se t({
  day: 20
});

Такой подход делает явным момент трансформации данных.


Цепочки трансформаций как основной стиль работы

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

const scheduled = DateTime.local(2024, 8, 1)
  .startOf('day')
  .plus({ hours: 9 })
  .setZone('Asia/Almaty');

Каждый вызов:

  • берёт предыдущий результат;
  • создаёт новый объект;
  • не затрагивает предыдущие значения.

Внутренняя модель данных

Внутри Luxon объекты DateTime содержат:

  • timestamp;
  • zone;
  • locale;
  • configuration metadata.

Эти данные фиксируются при создании и не изменяются, что позволяет:

  • кэшировать вычисления;
  • безопасно использовать объекты в разных контекстах;
  • избегать гонок состояния в асинхронных сценариях.

Иммутабельность и производительность

Хотя создание новых объектов может выглядеть затратным, Luxon оптимизирует операции:

  • минимизируется глубокое копирование;
  • используются внутренние кэши;
  • большинство операций — это лёгкие преобразования, а не полная пересборка структуры.

Баланс смещён в сторону предсказуемости, а не ручного управления состоянием.


Практический смысл неизменяемой модели

Иммутабельность формирует устойчивую модель работы с временем:

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