Как форматировать временные интервалы, например 2 часа 30 минут
Показывайте длительность на языке пользователя с автоматической локализацией
Введение
Когда вы показываете, сколько времени что-то занимает, важно отображать эту длительность так, чтобы пользователи понимали её. У видео может быть продолжительность 2 часа 30 минут, фитнес‑приложение считает время тренировки, а система управления проектами показывает время выполнения задач. Без локализации вы могли бы написать код так:
const hours = 2;
const minutes = 30;
const timeSpan = `${hours}h ${minutes}m`;
Это выведет "2h 30m" для всех пользователей вне зависимости от языка. Французские пользователи увидят "2h 30m" вместо привычного "2 h 30 min". Немцы увидят английские сокращения вместо "2 Std. 30 Min". Испанцам будет не хватать союзного "y" между единицами.
JavaScript предоставляет API Intl.DurationFormat для форматирования временных интервалов в соответствии с языком и культурными нормами пользователя. В этом уроке рассказывается, как создавать форматтеры длительностей, собирать объекты продолжительности и правильно отображать интервалы времени для любого языка.
Что такое временные интервалы
Временной интервал — это отрезок времени, а не момент. Число 150 минут — это длительность. 15 марта 2025 года в 14:30 — это дата и время.
Это различие важно, потому что даты связаны с календарями, часовыми поясами и историческими правилами. Временные интервалы измеряют прошедшее время вне контекста календаря. К длительности нельзя добавить часовой пояс, потому что она не привязана к какому-либо моменту.
Используйте Intl.DurationFormat для временных интервалов. Используйте Intl.DateTimeFormat для дат и времени. Используйте Intl.RelativeTimeFormat для относительных выражений типа "2 часа назад".
Создание форматтера длительности
Конструктор Intl.DurationFormat принимает локаль и объект параметров. Локаль определяет язык вывода, параметры — стиль форматирования и отображение единиц.
const formatter = new Intl.DurationFormat('en', { style: 'long' });
Вызовите format() с объектом продолжительности, чтобы получить форматированную строку. Объект продолжительности содержит числовые свойства для единиц времени.
const duration = { hours: 2, minutes: 30 };
formatter.format(duration);
// "2 hours and 30 minutes"
API автоматически обрабатывает сокращения, союзы, порядок слов и пробелы в зависимости от выбранной локали.
Создание объектов продолжительности
Объект продолжительности — это обычный объект JavaScript со свойствами для единиц времени. Указывайте только те единицы, которые нужно отображать.
const duration1 = { hours: 2, minutes: 30 };
const duration2 = { minutes: 5, seconds: 45 };
const duration3 = { hours: 1, minutes: 15, seconds: 30 };
API поддерживает следующие единицы времени: years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds.
Не обязательно указывать все единицы. Просто опустите те, которые не хотите отображать.
const formatter = new Intl.DurationFormat('en', { style: 'long' });
formatter.format({ hours: 2, minutes: 30 });
// "2 hours and 30 minutes"
formatter.format({ minutes: 30 });
// "30 minutes"
formatter.format({ hours: 2 });
// "2 hours"
Выбор стиля форматирования
Параметр style определяет плотность вывода. Доступно четыре стиля: long, short, narrow и digital.
Полный стиль использует целые слова. Используйте его для основного содержимого и текстов.
const duration = { hours: 2, minutes: 30 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "2 hours and 30 minutes"
Краткий стиль применяет общеупотребимые сокращения. Используйте его, если место ограничено, но важна читаемость.
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "2 hr and 30 min"
Узкий стиль использует минимум символов. Подходит для компактных интерфейсов, например, мобильных приложений или таблиц данных.
new Intl.DurationFormat('en', { style: 'narrow' }).format(duration);
// "2h 30m"
Цифровой стиль формирует вывод в формате таймера с двоеточиями. Этот вариант подходит для медиаплееров и счетчиков времени.
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "2:30:00"
В цифровом стиле нужно указывать все единицы от самой большой к самой маленькой. Например, если используете часы и минуты, обязательно добавьте и секунды.
Форматирование временных промежутков на разных языках
Один и тот же промежуток времени будет отображаться по-разному в зависимости от языка. API автоматически учтет все локализационные нюансы.
const duration = { hours: 2, minutes: 30 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "2 hours and 30 minutes"
new Intl.DurationFormat('fr', { style: 'long' }).format(duration);
// "2 heures et 30 minutes"
new Intl.DurationFormat('de', { style: 'long' }).format(duration);
// "2 Stunden und 30 Minuten"
new Intl.DurationFormat('es', { style: 'long' }).format(duration);
// "2 horas y 30 minutos"
new Intl.DurationFormat('ja', { style: 'long' }).format(duration);
// "2時間30分"
Обратите внимание, что в разных локалях используются разные слова и союзы. Например, во французском — «et», в немецком — «und», в испанском — «y», а в японском союзы не используются. API знает эти правила для каждого языка.
Краткие и узкие стили также корректно локализуются.
new Intl.DurationFormat('fr', { style: 'short' }).format(duration);
// "2 h et 30 min"
new Intl.DurationFormat('de', { style: 'narrow' }).format(duration);
// "2 Std. 30 Min."
Форматируйте промежутки времени с учётом локали пользователя
Вместо жёстко заданной локали используйте предпочитаемый язык пользователя из браузера. Свойство navigator.language возвращает основной языковой приоритет пользователя.
const userLocale = navigator.language;
const formatter = new Intl.DurationFormat(userLocale, { style: 'short' });
const duration = { hours: 2, minutes: 30 };
formatter.format(duration);
// Output varies by user's locale
// For en-US: "2 hr and 30 min"
// For de-DE: "2 Std. und 30 Min."
// For fr-FR: "2 h et 30 min"
Это позволяет отображать временные интервалы так, как ожидает каждый пользователь, без ручного выбора языка.
Преобразование миллисекунд в объекты длительности
Вычисления времени часто дают результат в миллисекундах. Преобразуйте миллисекунды в объекты длительности, деля их на соответствующие множители.
const milliseconds = 9000000; // 2 hours 30 minutes
const hours = Math.floor(milliseconds / 3600000);
const minutes = Math.floor((milliseconds % 3600000) / 60000);
const seconds = Math.floor((milliseconds % 60000) / 1000);
const duration = { hours, minutes, seconds };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "2 hours, 30 minutes and 0 seconds"
Опускайте нулевые значения, если только вам не нужно их отображать.
const duration = {};
if (hours > 0) duration.hours = hours;
if (minutes > 0) duration.minutes = minutes;
if (seconds > 0) duration.seconds = seconds;
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "2 hours and 30 minutes"
Вычисление промежутков времени между двумя датами
Вычислите длительность между двумя датами, вычитая их временные метки, а затем преобразуйте результат в объект длительности.
const startTime = new Date('2025-10-15T10:00:00');
const endTime = new Date('2025-10-15T12:30:00');
const diffMs = endTime - startTime;
const hours = Math.floor(diffMs / 3600000);
const minutes = Math.floor((diffMs % 3600000) / 60000);
const duration = { hours, minutes };
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "2 hr and 30 min"
Этот подход подходит для любых вычислений времени, которые дают результат в миллисекундах.
Форматирование длительности видео в плеерах
Видеоплееры показывают длительность в элементах управления. Для компактного отображения используйте цифровой или узкий стиль.
function formatVideoDuration(totalSeconds) {
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = Math.floor(totalSeconds % 60);
const duration = hours > 0
? { hours, minutes, seconds }
: { minutes, seconds };
const locale = navigator.language;
return new Intl.DurationFormat(locale, { style: 'digital' }).format(duration);
}
formatVideoDuration(9000); // "2:30:00"
formatVideoDuration(330); // "5:30"
При этом часы отображаются только при необходимости: короткие видео показаны как "5:30", а длиннее — как "2:30:00".
Форматирование длительности тренировок
Фитнес-приложения фиксируют продолжительность упражнения. Для итоговых экранов используйте длинный стиль, а для списков — узкий.
function formatWorkoutDuration(startTime, endTime, locale) {
const diffMs = endTime - startTime;
const hours = Math.floor(diffMs / 3600000);
const minutes = Math.floor((diffMs % 3600000) / 60000);
const duration = hours > 0
? { hours, minutes }
: { minutes };
return new Intl.DurationFormat(locale, { style: 'long' }).format(duration);
}
const workoutStart = new Date('2025-10-15T07:00:00');
const workoutEnd = new Date('2025-10-15T09:30:00');
formatWorkoutDuration(workoutStart, workoutEnd, 'en');
// "2 hours and 30 minutes"
formatWorkoutDuration(workoutStart, workoutEnd, 'es');
// "2 horas y 30 minutos"
Форматирование длительности задач в проектах
Инструменты управления проектами показывают, сколько времени заняла задача. Для дашбордов используйте краткий стиль.
function formatTaskDuration(minutes, locale) {
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
const duration = {};
if (hours > 0) duration.hours = hours;
if (mins > 0) duration.minutes = mins;
return new Intl.DurationFormat(locale, { style: 'short' }).format(duration);
}
formatTaskDuration(150, 'en');
// "2 hr and 30 min"
formatTaskDuration(45, 'en');
// "45 min"
formatTaskDuration(150, 'de');
// "2 Std. und 30 Min."
Форматирование разных единиц времени
Продолжительность может выражаться не только в часах и минутах. Форматируйте любые поддерживаемые комбинации единиц времени.
const formatter = new Intl.DurationFormat('en', { style: 'long' });
formatter.format({ days: 3, hours: 2 });
// "3 days and 2 hours"
formatter.format({ minutes: 45, seconds: 30 });
// "45 minutes and 30 seconds"
formatter.format({ hours: 1, minutes: 30, seconds: 45 });
// "1 hour, 30 minutes and 45 seconds"
API автоматически правильно расставляет союзы и разделители для любой комбинации единиц времени.
Форматирование временных промежутков только в секундах
Если длительность меньше минуты, указывайте только секунды.
const formatter = new Intl.DurationFormat('en', { style: 'short' });
formatter.format({ seconds: 45 });
// "45 sec"
formatter.format({ seconds: 5 });
// "5 sec"
Для очень коротких промежутков можно добавить миллисекунды.
formatter.format({ seconds: 5, milliseconds: 500 });
// "5 sec and 500 ms"
Переиспользуйте экземпляры форматтера для производительности
Создание нового форматтера требует загрузки локализованных данных и обработки опций. Если вам нужно отформатировать несколько промежутков времени с одной локалью и стилем, создайте форматтер один раз и используйте его повторно.
const formatter = new Intl.DurationFormat('en', { style: 'short' });
const durations = [
{ hours: 1, minutes: 30 },
{ hours: 2, minutes: 15 },
{ minutes: 45 }
];
durations.map(d => formatter.format(d));
// ["1 hr and 30 min", "2 hr and 15 min", "45 min"]
Этот подход повышает производительность при форматировании множества длительностей в циклах или при повторном рендере.
Поддержка браузеров
API Intl.DurationFormat стала базовой в марте 2025 года. Она работает в последних версиях Chrome, Edge, Firefox и Safari. Старые браузеры не поддерживают этот API.
Перед использованием API проверьте его поддержку.
if (typeof Intl.DurationFormat !== 'undefined') {
const formatter = new Intl.DurationFormat('en', { style: 'short' });
return formatter.format(duration);
} else {
return `${duration.hours}h ${duration.minutes}m`;
}
Такой подход обеспечивает резервное решение для старых браузеров, а при наличии — использует нативный API.