Конвертация длительности

В библиотеке Moment.js работа с временными интервалами реализована через объект duration, который предназначен для представления и преобразования длительностей независимо от конкретной даты. В отличие от объекта moment, который описывает точку во времени, duration оперирует промежутками: часами, минутами, секундами, днями и более крупными единицами.

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


Создание объекта длительности

Основной способ создания длительности:

const d = moment.duration(2, 'hours');

Допустимые единицы включают:

  • milliseconds
  • seconds
  • minutes
  • hours
  • days
  • weeks
  • months
  • years

Также возможно создание через объект:

const d = moment.duration({
  hours: 3,
  minutes: 45,
  seconds: 30
});

Или через общее количество миллисекунд:

const d = moment.duration(7200000);

Базовая конвертация длительности

Объект duration предоставляет набор методов для преобразования в различные единицы времени.

Миллисекунды

d.asMilliseconds();

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


Секунды, минуты и часы

d.asSeconds();
d.asMinutes();
d.asHours();

Каждый из методов возвращает значение в соответствующей единице с учётом дробной части.

Пример:

const d = moment.duration(90, 'minutes');

d.asHours();   // 1.5
d.asMinutes(); // 90
d.asSeconds(); // 5400

Дни и недели

d.asDays();
d.asWeeks();

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

const d = moment.duration(36, 'hours');

d.asDays(); // 1.5

Особенности работы с месяцами и годами

Месяцы и годы в duration являются неоднородными единицами. Один месяц может содержать 28, 29, 30 или 31 день, а год — 365 или 366 дней.

const d = moment.duration(1, 'month');

d.asDays(); // зависит от контекста и внутренней нормализации

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


Получение значений по компонентам

Помимо преобразования в одну единицу, duration позволяет извлекать отдельные компоненты:

d.hours();
d.minutes();
d.seconds();

Эти методы возвращают остаточные значения после нормализации.

Пример:

const d = moment.duration(2, 'hours')
  .add(30, 'minutes');

d.hours();   // 2
d.minutes(); // 30

Нормализация длительности

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

const d = moment.duration({
  minutes: 90,
  seconds: 120
});

Результат:

  • 90 минут → 1 час 30 минут
  • 120 секунд → 2 минуты

После нормализации:

d.hours();   // 1
d.minutes(); // 32
d.seconds(); // 0

Преобразование через универсальный метод as()

Метод as() позволяет получать значение в произвольной единице:

d.as('hours');
d.as('minutes');
d.as('seconds');

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


Преобразование и округление

Конвертация длительности часто требует округления значений:

Math.floor(d.asHours());
Math.ceil(d.asHours());
Math.round(d.asHours());

Moment.js не навязывает стратегию округления, предоставляя её на уровень приложения.


Изменение длительности перед конвертацией

Длительность может изменяться до преобразования:

const d = moment.duration(1, 'hour');

d.add(30, 'minutes');
d.subtract(10, 'minutes');

d.asMinutes(); // 80

Методы:

  • add
  • subtract

Работают с нормализацией и сохраняют внутреннюю структуру duration.


Получение ISO-строки длительности

Поддерживается формат ISO 8601:

d.toISOString();

Пример результата:

PT1H30M

Этот формат используется в API и системах обмена данными.


Человеко-читаемое представление

Метод humanize преобразует длительность в текстовое описание:

d.humanize();

Примеры:

  • “a few seconds”
  • “an hour”
  • “2 hours”

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


Конвертация с потерей точности

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

const d = moment.duration(1, 'year');

d.asDays();

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


Сравнение длительностей через конвертацию

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

const a = moment.duration(2, 'hours');
const b = moment.duration(90, 'minutes');

a.asMilliseconds() > b.asMilliseconds();

Этот подход исключает неоднозначность месяцев и лет.


Преобразование сложных составных длительностей

При создании длительности с несколькими компонентами:

const d = moment.duration({
  days: 1,
  hours: 5,
  minutes: 20,
  seconds: 10
});

Конвертация в различные единицы:

d.asHours();    // 29.335...
d.asMinutes();  // 1760.166...
d.asSeconds();  // 105610

Работа с отрицательными значениями

Duration поддерживает отрицательные интервалы:

const d = moment.duration(-2, 'hours');

Конвертация сохраняет знак:

d.asMinutes(); // -120

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

d.hours(); // 2 (при этом duration отрицательная)

Ограничения конвертации

Ключевые ограничения:

  • месяцы и годы не имеют фиксированной длительности
  • humanize не предназначен для точных вычислений
  • asX() возвращает дробные значения
  • компоненты hours/minutes/seconds зависят от нормализации

Эти особенности требуют выбора подходящего метода в зависимости от задачи: точные вычисления или отображение пользователю.


Преобразование длительности в объект и обратно

Duration может быть разобрана и восстановлена:

const d = moment.duration(2, 'hours');

const obj = {
  hours: d.hours(),
  minutes: d.minutes()
};

const restored = moment.duration(obj);

Такой подход используется при сериализации и хранении состояния времени.