Метод diff

Метод diff в Luxon используется для вычисления разницы между двумя моментами времени. Результатом работы метода является объект типа Duration, который хранит разницу в выбранных единицах измерения: от миллисекунд до лет.

Ключевая особенность метода заключается в том, что он не возвращает число, а формирует структурированное значение длительности, которое можно далее форматировать, конвертировать и анализировать.


Базовая сигнатура

Метод вызывается у экземпляра DateTime:

dt1.diff(dt2, units, options)

Где:

  • dt1 — исходный момент времени (тот, от которого считается разница)
  • dt2 — момент времени, с которым сравнивают
  • units — единицы измерения разницы
  • options — дополнительные параметры вычисления

Возвращаемое значение

Результатом всегда является объект Duration:

import { DateTime } from "luxon";

const dt1 = DateTime.local(2026, 1, 10);
const dt2 = DateTime.local(2026, 1, 1);

const diff = dt1.diff(dt2, "days");

diff содержит структуру:

  • значение разницы
  • единицы измерения
  • методы преобразования (toObject, toISO, shiftTo, и др.)

Единицы измерения

Luxon поддерживает как одиночные, так и комбинированные единицы.

Одиночные единицы

dt1.diff(dt2, "hours");
dt1.diff(dt2, "minutes");
dt1.diff(dt2, "seconds");
dt1.diff(dt2, "days");

Каждая единица возвращает число в соответствующем масштабе.


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

Можно передавать массив единиц:

dt1.diff(dt2, ["days", "hours", "minutes"]);

В этом случае результат распределяется по компонентам:

{
  days: 2,
  hours: 5,
  minutes: 30
}

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


Принцип вычисления разницы

Метод работает на основе абсолютной временной шкалы UTC внутри Luxon. Независимо от часового пояса входных значений, вычисление производится в унифицированном формате.

Пример:

const dt1 = DateTime.fromISO("2026-01-10T00:00:00+03:00");
const dt2 = DateTime.fromISO("2026-01-09T23:00:00Z");

Несмотря на разные зоны, Luxon приводит значения к UTC перед вычислением.


Направление разницы

Результат зависит от порядка аргументов:

dt1.diff(dt2)

означает:

dt1 - dt2

Если поменять аргументы:

dt2.diff(dt1)

результат станет отрицательным.

Пример:

const a = DateTime.local(2026, 1, 10);
const b = DateTime.local(2026, 1, 12);

a.diff(b, "days"); // -2 days
b.diff(a, "days"); // +2 days

Работа с дробными значениями

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

const dt1 = DateTime.local(2026, 1, 10);
const dt2 = DateTime.local(2026, 1, 9, 12);

const diff = dt1.diff(dt2, "days");

Результат:

1.5 days

Параметр options

Метод поддерживает объект опций:

dt1.diff(dt2, "hours", options);

conversionAccuracy

Опция управляет точностью преобразования между единицами.

dt1.diff(dt2, "months", { conversionAccuracy: "longterm" });

Возможные значения:

  • "casual" — быстрые приближённые вычисления
  • "longterm" — более точные расчёты с учётом календарных особенностей

Использование нескольких единиц

При указании массива единиц Luxon распределяет разницу от большей к меньшей единице.

const start = DateTime.local(2026, 1, 1);
const end = DateTime.local(2026, 1, 3, 4, 30);

const diff = end.diff(start, ["days", "hours", "minutes"]);

Результат:

{
  days: 2,
  hours: 4,
  minutes: 30
}

Важно, что перерасчёт происходит иерархически: сначала дни, затем остаток в часах, затем в минутах.


Метод diffNow

Существует специализированная версия:

DateTime.diffNow(units, options)

Он вычисляет разницу между текущим временем и заданным моментом:

const dt = DateTime.local(2026, 1, 1);

const diff = dt.diffNow("days");

Фактически эквивалентно:

DateTime.now().diff(dt, "days");

Преобразование результата

Объект Duration, возвращаемый diff, можно преобразовывать.

В объект

diff.toObject();

Пример:

{ days: 5, hours: 3 }

В ISO-формат

diff.toISO();

Результат:

P5DT3H

Переключение единиц

diff.shiftTo("hours", "minutes");

Позволяет перераспределить длительность в другие единицы без пересчёта исходных дат.


Особенности работы с календарными единицами

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

const a = DateTime.local(2026, 1, 31);
const b = DateTime.local(2026, 2, 28);

a.diff(b, "months");

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


Разница между diff и арифметикой дат

Обычные операции с DateTime возвращают новые даты, а не интервалы:

dt.plus({ days: 2 });

diff же возвращает длительность, а не момент времени:

dt1.diff(dt2);

Разделение этих концепций важно:

  • plus/minus → смещение времени
  • diff → измерение расстояния между точками

Типичные сценарии использования

Метод применяется для:

  • расчёта времени до события
  • измерения длительности процессов
  • вычисления возраста
  • построения таймеров и обратного отсчёта
  • анализа временных интервалов в логах

Обработка отрицательных значений

Отрицательная длительность не является ошибкой.

const diff = earlier.diff(later, "days");

Результат:

-3 days

Такие значения сохраняют корректную математическую интерпретацию направления разницы.


Точность и ограничения

При работе с большими интервалами и календарными единицами возможны нюансы:

  • месяцы и годы не имеют фиксированной длины
  • пересчёт зависит от выбранного conversionAccuracy
  • часовые пояса могут влиять на локальные представления, но не на UTC-вычисление

Цепочки преобразований

Результат diff часто используется в цепочках:

const result = dt1
  .diff(dt2, ["days", "hours"])
  .shiftTo("hours")
  .toObject();

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