Как форматировать временные интервалы, такие как 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('ru', { style: 'long' });
Вызовите format() с объектом длительности, чтобы получить отформатированную строку. Объект длительности содержит числовые свойства для единиц времени.
const duration = { hours: 2, minutes: 30 };
formatter.format(duration);
// "2 часа 30 минут"
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.
Стиль long использует полные слова. Используйте его для текста и основных областей контента.
const duration = { hours: 2, minutes: 30 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "2 hours and 30 minutes"
Стиль short использует общепринятые сокращения. Используйте его, когда пространство ограничено, но важна читаемость.
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "2 hr and 30 min"
Стиль narrow использует минимальное количество символов. Используйте его для компактных отображений, таких как мобильные интерфейсы или таблицы данных.
new Intl.DurationFormat('en', { style: 'narrow' }).format(duration);
// "2h 30m"
Стиль digital создает вывод, похожий на таймер, с двоеточиями. Используйте его для медиаплееров и отображения обратного отсчета.
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "2:30:00"
Для стиля digital необходимо включать все единицы от самой крупной до самой мелкой. Если вы форматируете часы и минуты, вы также должны включить секунды.
Форматирование временных интервалов на разных языках
Один и тот же временной интервал форматируется по-разному на каждом языке. 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);
// Вывод зависит от локали пользователя
// Для en-US: "2 hr and 30 min"
// Для de-DE: "2 Std. und 30 Min."
// Для fr-FR: "2 h et 30 min"
Это отображает временные интервалы в соответствии с ожиданиями каждого пользователя без необходимости ручного выбора локали.
Преобразование миллисекунд в объекты временных интервалов
Вычисления времени часто дают результат в миллисекундах. Преобразуйте миллисекунды в объекты длительности, разделив их на соответствующие множители.
const milliseconds = 9000000; // 2 часа 30 минут
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('ru', { style: 'long' }).format(duration);
// "2 часа, 30 минут и 0 секунд"
Пропускайте нулевые значения, если вы не хотите их отображать.
const duration = {};
if (hours > 0) duration.hours = hours;
if (minutes > 0) duration.minutes = minutes;
if (seconds > 0) duration.seconds = seconds;
new Intl.DurationFormat('ru', { style: 'long' }).format(duration);
// "2 часа и 30 минут"
Вычисление временных интервалов между двумя датами
Вычислите длительность между двумя датами, вычитая временные метки, а затем преобразуйте результат в объект длительности.
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('ru', { style: 'short' }).format(duration);
// "2 ч и 30 мин"
Этот подход работает для любых вычислений времени, которые дают результат в миллисекундах.
Форматирование длительности для видеоплееров
Видеоплееры отображают длительность в элементах управления. Используйте цифровой или узкий стиль для компактного отображения.
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('ru', { style: 'short' });
formatter.format({ seconds: 45 });
// "45 сек"
formatter.format({ seconds: 5 });
// "5 сек"
Для очень коротких интервалов можно включить миллисекунды.
formatter.format({ seconds: 5, milliseconds: 500 });
// "5 сек и 500 мс"
Повторное использование экземпляров форматтера для повышения производительности
Создание нового форматтера включает загрузку данных локали и обработку параметров. Если вы форматируете несколько временных интервалов с одной и той же локалью и стилем, создайте форматтер один раз и используйте его повторно.
const formatter = new Intl.DurationFormat('ru', { style: 'short' });
const durations = [
{ hours: 1, minutes: 30 },
{ hours: 2, minutes: 15 },
{ minutes: 45 }
];
durations.map(d => formatter.format(d));
// ["1 ч и 30 мин", "2 ч и 15 мин", "45 мин"]
Этот подход улучшает производительность при форматировании множества временных интервалов в циклах или при повторных рендерах.
Поддержка браузерами
API Intl.DurationFormat стало доступно в марте 2025 года. Оно работает в последних версиях Chrome, Edge, Firefox и Safari. Старые браузеры не поддерживают это API.
Проверьте поддержку перед использованием API.
if (typeof Intl.DurationFormat !== 'undefined') {
const formatter = new Intl.DurationFormat('ru', { style: 'short' });
return formatter.format(duration);
} else {
return `${duration.hours}ч ${duration.minutes}м`;
}
Это обеспечивает резервный вариант для старых браузеров, используя нативное API, если оно доступно.