Вычисление разницы в различных единицах

В Day.js вычисление разницы между двумя моментами времени выполняется методом diff(). Его базовая форма:

dayjs(end).diff(dayjs(start), unit)

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

Поддерживаемые единицы:

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

Разница в миллисекундах

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

const start = dayjs('2026-01-01T00:00:00.000');
const end = dayjs('2026-01-01T00:00:01.250');

const diff = end.diff(start, 'millisecond');

Результат будет:

1250

Разница в миллисекундах всегда линейна и не зависит от календарных особенностей.


Разница в секундах, минутах и часах

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

const start = dayjs('2026-01-01T00:00:00');
const end = dayjs('2026-01-01T00:05:30');

end.diff(start, 'second'); // 330
end.diff(start, 'minute'); // 5
end.diff(start, 'hour');   // 0

Особенность поведения:

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

Для получения дробного результата используется третий аргумент:

end.diff(start, 'minute', true); // 5.5

Разница в днях

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

const start = dayjs('2026-01-01');
const end = dayjs('2026-01-10');

end.diff(start, 'day'); // 9

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


Разница в неделях

Неделя интерпретируется как 7 дней без учета локальных календарных особенностей.

const start = dayjs('2026-01-01');
const end = dayjs('2026-01-22');

end.diff(start, 'week'); // 3

Каждая неделя — это строго 7 дней, без привязки к понедельнику или воскресенью.


Разница в месяцах

Месяцы имеют переменную длину, что делает вычисление менее линейным.

const start = dayjs('2026-01-01');
const end = dayjs('2026-04-01');

end.diff(start, 'month'); // 3

При вычислении месяцев учитываются календарные переходы, а не фиксированное количество дней.

Пример неоднозначности:

dayjs('2026-02-28').diff(dayjs('2026-01-31'), 'month'); // 0

Причина: неполный календарный месяц не засчитывается.


Разница в годах

Годы вычисляются как количество полных календарных циклов.

const start = dayjs('2020-01-01');
const end = dayjs('2026-01-01');

end.diff(start, 'year'); // 6

При этом високосные годы учитываются автоматически через календарную модель.


Дробные значения и точность вычислений

Третий аргумент diff() позволяет получать дробные результаты.

const start = dayjs('2026-01-01T00:00:00');
const end = dayjs('2026-01-01T12:00:00');

end.diff(start, 'day', true); // 0.5
end.diff(start, 'hour', true); // 12

Поведение:

  • false или отсутствие аргумента → целое число
  • true → число с плавающей точкой

Обратная разница и отрицательные значения

Порядок аргументов влияет на знак результата.

dayjs('2026-01-10').diff(dayjs('2026-01-01'), 'day'); // 9
dayjs('2026-01-01').diff(dayjs('2026-01-10'), 'day'); // -9

Метод не нормализует знак, он строго отражает направление вычисления.


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

При использовании локального времени возможны расхождения из-за переходов времени и DST.

const a = dayjs('2026-03-29T01:00:00');
const b = dayjs('2026-03-29T03:00:00');

b.diff(a, 'hour'); // может быть 1 или 2 в зависимости от DST

Для стабильных вычислений используется UTC-плагин:

import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);

const a = dayjs.utc('2026-03-29T01:00:00');
const b = dayjs.utc('2026-03-29T03:00:00');

b.diff(a, 'hour'); // 2

Сравнение с началом и концом периода

Часто разница используется для вычисления длины интервалов.

const startOfMonth = dayjs().startOf('month');
const endOfMonth = dayjs().endOf('month');

endOfMonth.diff(startOfMonth, 'day');

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

  • startOf() нормализует время к началу единицы
  • endOf() устанавливает конец единицы

Это важно при расчёте длительности календарных периодов.


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

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

const start = dayjs('2026-01-01');
const end = dayjs('2026-03-15');

const months = end.diff(start, 'month');
const days = end.diff(start.add(months, 'month'), 'day');

Такой подход позволяет строить составные интервалы: «X месяцев Y дней».


Особенности работы с месяцами разной длины

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

dayjs('2026-01-31').diff(dayjs('2026-02-28'), 'month'); // 0

Причина:

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

Поведение при одинаковых датах

const a = dayjs('2026-01-01');
const b = dayjs('2026-01-01');

b.diff(a, 'day'); // 0

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


Использование с длительностями (Duration plugin)

Для более сложных операций разницы часто преобразуются в объект длительности:

import duration from 'dayjs/plugin/duration';
dayjs.extend(duration);

const diff = dayjs('2026-01-10').diff(dayjs('2026-01-01'), 'hour');

const d = dayjs.duration(diff, 'hour');

Это позволяет выполнять дальнейшие операции:

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

Сравнение diff с другими методами

Помимо diff(), используются:

  • isBefore()
  • isAfter()
  • isSame()

Они не возвращают числовую разницу, но часто комбинируются с diff() для условной логики.

if (end.isAfter(start)) {
  const days = end.diff(start, 'day');
}

Типичные ошибки при вычислении разницы

  1. Игнорирование усечения дробной части

    end.diff(start, 'hour'); // может потерять минуты
  2. Использование локального времени без учета DST приводит к некорректным часовым интервалам

  3. Предположение фиксированной длины месяца месяц не равен 30 дням

  4. Смешивание единиц без нормализации требует явного контроля переходов


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

При обработке больших массивов дат:

  • создание объектов Day.js дешевле, чем использование Date
  • diff() выполняется в константное время
  • узким местом становится парсинг входных строк

Оптимизация:

const start = dayjs('2026-01-01');

const results = dates.map(d => dayjs(d).diff(start, 'day'));

Стабильность вычислений в разных единицах

Общее правило поведения:

  • мелкие единицы → точная линейная арифметика
  • крупные единицы → календарная модель
  • месяцы и годы → нелинейная логика

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