Цепочки операций

В библиотеке Day.js архитектура построена вокруг неизменяемых объектов даты. Это означает, что каждый метод, который модифицирует дату, не изменяет исходный экземпляр, а возвращает новый объект. Именно это свойство делает возможной и удобной цепочку операций.

Цепочка методов формируется за счёт того, что каждый вызов возвращает экземпляр Day.js, поддерживающий тот же набор методов. Это позволяет последовательно применять преобразования без промежуточных переменных.

dayjs()
  .add(2, 'day')
  .subtract(3, 'hour')
  .startOf('month')
  .format('YYYY-MM-DD HH:mm:ss')

Каждый шаг создаёт новый объект даты, передавая его дальше по цепочке. Такой подход исключает побочные эффекты и упрощает предсказуемость вычислений.


Неизменяемость как основа цепочек

Ключевое свойство Day.js — immutable (неизменяемость). Любая операция возвращает новый экземпляр, сохраняя исходный объект неизменным.

const base = dayjs();

const result = base.add(1, 'day');

base.format('YYYY-MM-DD');
result.format('YYYY-MM-DD');

Здесь base остаётся неизменным, даже после выполнения add. Это критично для цепочек, так как гарантирует отсутствие скрытых изменений состояния.

Если бы объект изменялся, последовательность вызовов становилась бы непредсказуемой:

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

Базовая структура цепочки

Цепочка операций в Day.js обычно начинается с создания экземпляра и продолжается набором преобразований.

Типичный шаблон

dayjs()
  .operation()
  .operation()
  .operation()

Каждый метод в цепочке возвращает новый Day.js объект, кроме финальных методов, возвращающих строку или число (например, format, valueOf, unix).


Арифметические операции в цепочках

Добавление и вычитание времени

Методы add и subtract являются основными инструментами для трансформации даты.

dayjs()
  .add(7, 'day')
  .subtract(2, 'month')
  .add(3, 'hour')

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

Особенность заключается в единообразной системе единиц времени:

  • millisecond
  • second
  • minute
  • hour
  • day
  • week
  • month
  • year

Комбинирование разных единиц

Цепочки позволяют строить сложные временные преобразования:

dayjs()
  .add(1, 'year')
  .subtract(10, 'day')
  .add(6, 'month')
  .subtract(2, 'hour')

Такой стиль делает логику изменения даты линейной и читаемой.


Операции округления времени

Методы startOf и endOf часто используются в цепочках для нормализации даты.

Начало периода

dayjs()
  .add(5, 'day')
  .startOf('month')

Здесь сначала происходит смещение даты, затем она приводится к началу месяца.

Конец периода

dayjs()
  .subtract(1, 'year')
  .endOf('year')

Операции округления часто завершают цепочку, так как возвращают конкретное фиксированное значение.


Форматирование как завершающий этап цепочки

Метод format завершает цепочку, преобразуя объект даты в строку.

dayjs()
  .add(2, 'day')
  .startOf('hour')
  .format('YYYY-MM-DD HH:mm')

После вызова format дальнейшие методы цепочки невозможны, так как результатом становится строка.

Типичные форматы

  • YYYY-MM-DD
  • DD.MM.YYYY
  • YYYY-MM-DD HH:mm:ss
  • ddd, MMM D YYYY

Получение числовых значений

Некоторые методы также завершают цепочку, возвращая число.

dayjs()
  .add(10, 'day')
  .valueOf()

или

dayjs()
  .unix()

Такие методы используются при необходимости интеграции с API, базами данных или таймстампами.


Вложенные цепочки и промежуточные переменные

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

const baseDate = dayjs();

const future = baseDate
  .add(1, 'month')
  .startOf('month');

const formatted = future.format('YYYY-MM-DD');

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


Разветвление цепочек

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

const base = dayjs();

const a = base.add(1, 'day').format('YYYY-MM-DD');
const b = base.add(1, 'month').format('YYYY-MM-DD');

Здесь base остаётся независимой точкой отсчёта для разных вычислений.


Цепочки с плагинами

Day.js поддерживает плагины, которые расширяют цепочные операции дополнительными методами.

Пример: UTC

dayjs()
  .utc()
  .add(3, 'day')
  .format()

Пример: timezone

dayjs()
  .tz('Europe/Moscow')
  .add(5, 'hour')
  .format()

Подключение плагинов не нарушает принцип цепочек: новые методы интегрируются в стандартный API.


Внутренняя модель цепочного выполнения

Цепочка в Day.js представляет собой последовательную передачу нового экземпляра:

  1. Создание объекта
  2. Выполнение метода → новый объект
  3. Передача нового объекта в следующий метод
  4. Завершение цепочки при вызове терминального метода

Эта модель исключает состояние «внутри объекта» и заменяет его функциональным подходом.


Ошибки при работе с цепочками

Потеря результата

dayjs().add(1, 'day');

Без сохранения результата или дальнейшего вызова метод не имеет эффекта в логике программы.


Попытка продолжить после терминального метода

dayjs()
  .add(1, 'day')
  .format('YYYY-MM-DD')
  .add(1, 'month'); // ошибка

После format объект превращается в строку.


Неправильное ожидание мутации

const d = dayjs();
d.add(1, 'day');
d.format(); // исходная дата без изменений

Такое поведение часто становится источником логических ошибок при отсутствии понимания неизменяемости.


Композиция сложных выражений

Цепочки позволяют выражать бизнес-логику времени компактно.

dayjs()
  .add(2, 'month')
  .startOf('month')
  .add(7, 'day')
  .endOf('day')
  .format('YYYY-MM-DD HH:mm:ss')

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


Читаемость и порядок операций

В цепочках важен порядок:

  • операции выполняются слева направо
  • каждый шаг опирается на результат предыдущего
  • логика должна быть линейной
dayjs()
  .add(1, 'day')
  .startOf('day')
  .add(3, 'hour')

Изменение порядка вызовов изменяет итоговый результат, что делает цепочки чувствительными к структуре.


Ограничения цепочного подхода

Несмотря на удобство, цепочки имеют особенности:

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

В таких случаях используется разбиение на переменные, сохраняя при этом неизменяемость объектов Day.js.


Сочетание цепочек и функционального стиля

Цепочки в Day.js хорошо сочетаются с функциональными подходами:

const transformDate = (d) =>
  d.add(1, 'year').startOf('year');

transformDate(dayjs()).format('YYYY-MM-DD');

Здесь цепочка инкапсулируется в функцию, сохраняя переиспользуемость и читаемость.