В библиотеке Luxon длительность (Duration) представляет собой абстракцию промежутка времени, независимого от конкретной даты и часового пояса. Внутренне Duration хранится как набор полей: годы, месяцы, недели, дни, часы, минуты, секунды и миллисекунды. Такой подход позволяет описывать как короткие интервалы (например, 1500 миллисекунд), так и сложные составные длительности (например, 1 год 2 месяца 3 дня 4 часа).
Основная особенность формата Duration заключается в том, что он не привязан к абсолютной точке времени. Это приводит к необходимости аккуратного преобразования и форматирования, поскольку разные единицы могут требовать нормализации и приведения к удобному виду.
Нормализация играет ключевую роль перед форматированием. Метод
normalize() перераспределяет значения между единицами,
например, 90 секунд превращаются в 1 минуту 30 секунд, но только в
пределах доступных единиц.
Для преобразования Duration в строку используется несколько подходов, каждый из которых ориентирован на разные сценарии отображения.
Одним из стандартных представлений является ISO 8601 Duration формат. Он используется для обмена данными между системами и строго стандартизирован.
Метод toISO() возвращает строку в формате:
Пример:
import { Duration } from "luxon";
const d = Duration.fromObject({
hours: 2,
minutes: 30,
seconds: 15
});
d.toISO(); // "PT2H30M15S"
ISO-формат удобен для сериализации, но не предназначен для человекочитаемого отображения.
Метод toObject() возвращает структуру, которая
соответствует внутреннему состоянию Duration.
d.toObject();
// { hours: 2, minutes: 30, seconds: 15 }
Это представление используется в основном для отладки и промежуточных вычислений, а не для форматирования пользовательского интерфейса.
Одним из наиболее гибких способов отображения Duration является
toHuman(). Он преобразует длительность в строку, учитывая
локализацию и ненулевые единицы.
d.toHuman();
// "2 hours, 30 minutes, 15 seconds"
Особенности поведения:
При необходимости можно контролировать формат через опции:
d.toHuman({ unitDisplay: "short" });
// "2 hr, 30 min, 15 sec"
Также доступна настройка локали:
d.setLocale("ru").toHuman();
// "2 часа, 30 минут, 15 секунд"
Наиболее мощный инструмент форматирования Duration —
toFormat. Он использует токены, аналогичные форматированию
дат, но адаптированные под длительности.
Основная идея заключается в описании шаблона, где каждый символ соответствует определённой единице времени.
Пример базового использования:
const d = Duration.fromObject({
hours: 5,
minutes: 7,
seconds: 9
});
d.toFormat("hh:mm:ss");
// "05:07:09"
h — часыm — минутыs — секундыS — миллисекундыd — дни (в зависимости от контекста)M — месяцыy — годыПовторение символа влияет на форматирование:
h — без ведущих нулейhh — с ведущим нулём (два знака)hhh — расширенный формат (при больших значениях)Пример различий:
const d = Duration.fromObject({ hours: 3 });
d.toFormat("h"); // "3"
d.toFormat("hh"); // "03"
Форматирование позволяет комбинировать различные части длительности:
const d = Duration.fromObject({
days: 1,
hours: 4,
minutes: 20
});
d.toFormat("d 'days' hh:mm");
// "1 days 04:20"
Кавычки используются для вставки литерального текста без интерпретации токенов.
Перед применением toFormat часто требуется привести
Duration к согласованному виду. Без этого возможны неожиданные
результаты, например, наличие 90 минут вместо 1 часа 30 минут.
const d = Duration.fromObject({
hours: 1,
minutes: 90
});
d.toFormat("hh:mm");
// "01:90"
d.normalize().toFormat("hh:mm");
// "02:30"
Нормализация особенно важна при работе с пользовательским вводом или агрегированием временных интервалов.
Luxon позволяет использовать shiftTo для управления тем,
какие единицы будут участвовать в форматировании.
const d = Duration.fromObject({
seconds: 3600
}).shiftTo("hours", "minutes");
d.toFormat("hh:mm");
// "01:00"
Этот подход используется для создания строгих интерфейсов отображения, где допустимы только определённые единицы.
Форматирование Duration может учитывать локаль, особенно при
использовании toHuman. В случае toFormat
локализация не влияет напрямую на токены, но может использоваться
совместно с преобразованием единиц.
const d = Duration.fromObject({
hours: 2,
minutes: 15
}).setLocale("fr");
d.toHuman();
// "2 heures, 15 minutes"
Локализация особенно важна в интерфейсах, где длительность отображается пользователю, а не используется технически.
Миллисекунды требуют отдельного внимания, так как часто используются в измерении производительности и анимаций.
const d = Duration.fromObject({
seconds: 1,
milliseconds: 250
});
d.toFormat("s.SS");
// "1.25"
Количество S влияет на точность отображения:
S — десятки миллисекундSS — сотни миллисекундSSS — полные миллисекундыПри отсутствии явной структуры Duration может содержать смешанные единицы, требующие приведения перед форматированием.
const d = Duration.fromObject({
minutes: 125
});
d.toFormat("hh:mm");
// "02:125"
d.normalize().toFormat("hh:mm");
// "02:05"
Такие ситуации возникают при агрегации данных из разных источников.
Duration поддерживает масштабные значения, включая годы и месяцы. Однако их форматирование требует аккуратного выбора шаблонов, поскольку месяцы и годы не имеют фиксированной длительности в миллисекундах.
const d = Duration.fromObject({
years: 1,
months: 2,
days: 10
});
d.toFormat("y-MM-dd");
// "1-02-10"
При интерпретации таких значений важно учитывать контекст: календарные единицы не эквивалентны фиксированному времени.
Duration может содержать отрицательные компоненты, и форматирование в таком случае сохраняет знак результата.
const d = Duration.fromObject({
minutes: -90
}).normalize();
d.toFormat("hh:mm");
// "-01:30"
Отрицательные длительности часто используются при вычислении разницы между временными метками.
Форматирование Duration редко используется изолированно. Чаще оно является завершающим этапом цепочки преобразований:
Duration.fromObject({ seconds: 5000 })
.shiftTo("hours", "minutes", "seconds")
.normalize()
.toFormat("hh:mm:ss");
Такой подход обеспечивает предсказуемость результата при сложных вычислениях длительности.