Сравнение длительностей

Представление длительности и базовая модель сравнения

В Moment.js длительности представлены через moment.duration, где значение хранится как набор временных единиц и одновременно как нормализованное количество миллисекунд. Основой для корректного сравнения выступает приведение к единой числовой шкале, поскольку разные единицы измерения не эквивалентны по внутренней структуре.

const d1 = moment.duration(2, 'hours');
const d2 = moment.duration(120, 'minutes');

Несмотря на различие в способе задания, обе длительности фактически эквивалентны в абсолютном времени.


Приведение длительностей к единой шкале

Любая длительность в Moment.js может быть приведена к миллисекундам, секундам, минутам и другим единицам через методы asX().

const d1 = moment.duration(1, 'day');
const d2 = moment.duration(24, 'hours');

d1.asHours(); // 24
d2.asHours(); // 24

Для сравнения используется строгое числовое значение:

  • asMilliseconds()
  • asSeconds()
  • asMinutes()
  • asHours()
  • asDays()

Приведение к одной единице устраняет неоднозначность сравнения.


Сравнение через valueOf и операторы

Внутренне длительность хранит эквивалент в миллисекундах, что позволяет использовать числовое сравнение через valueOf().

const d1 = moment.duration(5000);
const d2 = moment.duration(3000);

d1.valueOf() > d2.valueOf(); // true
d1 > d2; // true (неявное приведение)

Операторы сравнения (>, <, >=, <=) работают корректно, поскольку объект приводит себя к числу через valueOf.


Эквивалентность длительностей

Проверка равенства требует строгого сравнения числовых значений:

const d1 = moment.duration(2, 'hours');
const d2 = moment.duration(120, 'minutes');

d1.asMilliseconds() === d2.asMilliseconds(); // true

Прямое сравнение объектов не применяется:

d1 === d2; // false

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

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

const d1 = moment.duration(1, 'hour');
const d2 = moment.duration(90, 'minutes');

d1.asMinutes() < d2.asMinutes(); // true

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


Сравнение через разницу временных точек

Часто длительности получаются как результат разницы между моментами времени:

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

const diff = moment.duration(end.diff(start));

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

diff.asDays(); // 2

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


Нормализация и скрытые несоответствия

Длительности могут хранить остаточные значения в разных единицах, например:

const d = moment.duration({
  days: 1,
  hours: 25
});

Внутренне это преобразуется в:

  • 2 дня и 1 час (в зависимости от нормализации при вызове методов)

Для корректного сравнения требуется обращение к абсолютной шкале:

d.asHours();
d.asMilliseconds();

Сравнение полей объекта напрямую (d.days, d.hours) не отражает фактическую величину.


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

Некоторые единицы в Moment.js не являются фиксированными по длине:

  • месяцы
  • годы
const d1 = moment.duration(1, 'month');
const d2 = moment.duration(30, 'days');

Сравнение этих значений через asDays() может давать неоднозначный результат, поскольку:

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

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


Лексикографическое и числовое сравнение

Moment.js не предоставляет отдельного механизма лексикографического сравнения длительностей. Все сравнения сводятся к числовым значениям:

const durations = [
  moment.duration(10, 'minutes'),
  moment.duration(1, 'hour'),
  moment.duration(30, 'minutes')
];

durations.sort((a, b) => a - b);

Фактически используется преобразование через valueOf().


Сравнение с учётом точности

При работе с большими наборами данных возникают ошибки округления:

const d1 = moment.duration(0.1, 'seconds');
const d2 = moment.duration(100, 'milliseconds');

d1.asMilliseconds() === d2.asMilliseconds(); // true

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


Практический паттерн унифицированного сравнения

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

function compareDurations(a, b) {
  return a.asMilliseconds() - b.asMilliseconds();
}

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


Сравнение длительностей, полученных из дат

При работе с временными интервалами, основанными на датах:

const a = moment('2026-01-01 10:00');
const b = moment('2026-01-01 12:30');

const duration = moment.duration(b.diff(a));

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

duration.asMinutes(); // 150

Ограничения и неоднозначности сравнения

Сравнение длительностей становится неоднозначным при:

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

В таких случаях единственным стабильным критерием остаётся миллисекундное представление:

duration.valueOf()