Клонирование объектов

Библиотека Luxon построена на принципе иммутабельности объектов времени. Это означает, что любой объект DateTime, Duration или Interval не изменяется после создания. Любая операция над ним возвращает новый экземпляр, а исходный объект остаётся неизменным.

Такой подход напрямую определяет модель «клонирования»: в большинстве случаев отдельный механизм clone() не требуется, поскольку каждая модификация уже является формой копирования.

Ключевая особенность:

  • исходные объекты не мутируют состояние
  • любые изменения создают новый объект
  • «копирование» фактически встроено в API преобразований

DateTime: логика копирования через преобразования

Базовый принцип

Объект DateTime не имеет универсального метода глубокого клонирования. Вместо этого используются операции, которые возвращают новый экземпляр с изменёнными параметрами.

const dt1 = DateTime.now();
const dt2 = dt1.set({ hour: 10 });

Здесь dt2 — новый объект, а dt1 остаётся неизменным.


Копирование через set

Метод set создаёт модифицированную копию:

const original = DateTime.local(2024, 5, 10, 12, 0);

const copy = original.set({
  hour: 18,
  minute: 30
});

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

  • изменяются только указанные поля
  • остальные компоненты времени сохраняются
  • возвращается новый экземпляр DateTime

Копирование через изменение зоны

Изменение временной зоны также является формой клонирования:

const utc = DateTime.utc();
const msk = utc.setZone('Europe/Moscow');

setZone:

  • не модифицирует исходный объект
  • создаёт новый DateTime
  • пересчитывает внутреннее представление времени

Клонирование через reconfigure

При необходимости изменить конфигурацию объекта (например, зональность или локаль) используется:

const dt = DateTime.local();

const adjusted = dt.reconfigure({
  zone: 'utc',
  locale: 'ru'
});

Это также создаёт новый экземпляр, фактически выполняя «копирование с настройками».


Полное восстановление объекта

Если требуется получить независимую копию без изменений состояния, используется сериализация:

const dt1 = DateTime.local(2024, 5, 10, 12, 0);

const dt2 = DateTime.fromObject(dt1.toObject());

Механизм:

  • toObject() извлекает структурированные поля
  • fromObject() создаёт новый экземпляр
  • результат — полная логическая копия

Копирование через ISO-представление

Ещё один универсальный способ:

const dt1 = DateTime.local();

const dt2 = DateTime.fromISO(dt1.toISO());

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

  • сохраняется точность времени
  • сохраняется часовой пояс (если он включён в строку)
  • создаётся независимый объект

Duration: копирование через арифметику

Объект Duration также неизменяем.

Основной способ клонирования

Любая операция возвращает новый экземпляр:

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

const d2 = d1.plus({ minutes: 30 });

Здесь d2 — копия с изменением, а d1 остаётся неизменным.


Явное копирование через toObject

const d1 = Duration.fromObject({ hours: 5, minutes: 15 });

const d2 = Duration.fromObject(d1.toObject());

Механизм аналогичен DateTime:

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

Клонирование с нормализацией

Иногда требуется «пересборка» длительности:

const d1 = Duration.fromObject({ minutes: 120 });

const d2 = Duration.fromMillis(d1.as('milliseconds'));

Такой подход полезен при:

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

Interval: полноценное клонирование через clone

В отличие от DateTime, объект Interval предоставляет явный метод копирования.

const interval1 = Interval.fromDateTimes(
  DateTime.local(2024, 1, 1),
  DateTime.local(2024, 1, 10)
);

const interval2 = interval1.clone();

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

Метод:

  • создаёт новый объект Interval
  • копирует start и end как независимые DateTime
  • сохраняет неизменность исходных данных

Важно:

  • вложенные DateTime также являются неизменяемыми
  • поэтому глубокое копирование не требуется в классическом смысле

Ручное копирование интервала

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

const interval2 = Interval.fromDateTimes(
  interval1.start,
  interval1.end
);

Такой вариант эквивалентен clone(), но более явный.


Глубокое копирование: структурный подход

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

DateTime → структура → DateTime

const original = DateTime.local();

const copy = DateTime.fromObject(original.toObject());

Duration → структура → Duration

const original = Duration.fromObject({ hours: 3 });

const copy = Duration.fromObject(original.toObject());

Interval → разбор и сборка

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

const copy = Interval.fromDateTimes(
  DateTime.fromISO(original.start.toISO()),
  DateTime.fromISO(original.end.toISO())
);

Почему в Luxon нет классического clone для DateTime

Архитектура библиотеки исключает необходимость универсального клонирования:

  1. Иммутабельность устраняет риск побочных эффектов
  2. Методы трансформации уже возвращают новые объекты
  3. Структурная сериализация заменяет глубокие копии
  4. Минимизация состояния упрощает управление экземплярами

Фактически, clone как отдельная концепция избыточен для DateTime.


Поведение при цепочках операций

Каждая операция создаёт новый объект, что позволяет строить цепочки:

const result = DateTime.local()
  .set({ hour: 8 })
  .plus({ days: 1 })
  .setZone('utc');

Каждый шаг:

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

Практические паттерны копирования

Фиксация состояния времени

const snapshot = DateTime.now();

Любая дальнейшая модификация не влияет на snapshot.


Базовый шаблон с изменениями

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

const modified = base
  .set({ month: 6 })
  .plus({ days: 10 });

Создание независимых веток времени

const base = DateTime.local();

const branch1 = base.plus({ hours: 1 });
const branch2 = base.plus({ hours: 2 });

Ошибки при попытке «ручного клонирования»

Попытка мутации

const dt1 = DateTime.local();
dt1.hour = 10; // не работает

Объект остаётся неизменным, изменение игнорируется.


Поверхностное копирование не требуется

const copy = { ...DateTime.local() };

Такой подход:

  • не создаёт валидный DateTime
  • ломает внутреннюю структуру объекта
  • приводит к потере методов

Итоговая модель копирования в Luxon

Вся система копирования сводится к трём принципам:

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

Каждый тип объекта реализует собственный способ создания независимых экземпляров, при этом сохраняя единый подход: любой «клон» — это всегда новый объект, полученный через трансформацию или сборку из данных.