Как форматировать временные интервалы, например 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.