Как отформатировать длительность как 2:30:45?

Показ времени в формате цифровых часов с двоеточиями

Введение

Видеоплееры, секундомеры и таймеры обратного отсчёта показывают длительность в привычном формате. Вы видите «2:30:45» и сразу понимаете, что это 2 часа, 30 минут и 45 секунд. Такой цифровой формат использует двоеточия для разделения единиц времени без подписей и пробелов.

Чтобы собрать такой формат вручную, нужно дополнять числа нулями и учитывать разную длину длительности. Видео на 5 минут 30 секунд отображается как «5:30», а двухчасовое видео — как «2:00:00». Логика усложняется из-за разных случаев.

function formatDuration(seconds) {
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = Math.floor(seconds % 60);

  if (h > 0) {
    return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
  }
  return `${m}:${String(s).padStart(2, '0')}`;
}

API Intl.DurationFormat делает это автоматически с опцией стиля digital. Она выдаёт правильный формат для любой длительности.

const duration = { hours: 2, minutes: 30, seconds: 45 };
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "2:30:45"

Используйте цифровой стиль для таймеров

Стиль digital форматирует длительность как на цифровых часах. Установите опцию style в значение "digital" при создании форматтера.

const formatter = new Intl.DurationFormat('en', { style: 'digital' });

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

const duration = { hours: 1, minutes: 5, seconds: 30 };
formatter.format(duration);
// "1:05:30"

Обратите внимание, что минуты отображаются как «05», а не «5». Форматтер сам дополняет минуты до двух знаков, если есть часы. Это удобно для выравнивания в списках и таблицах.

Если в длительности нет часов, просто не указывайте это свойство в объекте.

const shortDuration = { minutes: 5, seconds: 30 };
formatter.format(shortDuration);
// "5:30"

Если часы отсутствуют, минуты не нужно дополнять нулями. Формат остаётся компактным и понятным.

Как цифровой формат обрабатывает разную длительность

Цифровой формат подстраивает вывод в зависимости от того, какие единицы времени вы указываете в объекте длительности. Это похоже на то, как видеоплееры меняют отображение в зависимости от длины видео.

Короткая длительность показывает только минуты и секунды.

const formatter = new Intl.DurationFormat('en', { style: 'digital' });

const short = { minutes: 3, seconds: 42 };
formatter.format(short);
// "3:42"

Для более длинной длительности добавляются часы.

const long = { hours: 2, minutes: 15, seconds: 8 };
formatter.format(long);
// "2:15:08"

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

Это правило дополнения нулями обеспечивает ровное выравнивание без лишнего пространства. В списке коротких видео будет «5:30», «12:45», «8:02» — двоеточия выровнены. В списке длинных видео — «1:05:30», «2:12:45», «3:08:02» — форматирование всегда одинаковое.

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

const countdown = { minutes: 42, seconds: 15 };
formatter.format(countdown);
// "42:15"

Управление нулями и вариантами отображения

В цифровом формате используются стандартные правила дополнения нулями, но вы можете их изменить, указав опции для отдельных единиц времени.

Управляйте отображением каждой единицы времени с помощью индивидуальных опций. Значение numeric показывает число без дополнения нулями. Значение 2-digit всегда добавляет ведущий ноль.

const duration = { hours: 1, minutes: 5, seconds: 3 };

new Intl.DurationFormat('en', {
  style: 'digital',
  hours: 'numeric',
  minutes: '2-digit',
  seconds: '2-digit'
}).format(duration);
// "1:05:03"

Это поведение по умолчанию. Указывать эти опции нужно только если хотите другой формат.

Принудительно показывайте часы всегда с двумя знаками.

new Intl.DurationFormat('en', {
  style: 'digital',
  hours: '2-digit',
  minutes: '2-digit',
  seconds: '2-digit'
}).format(duration);
// "01:05:03"

Этот формат отлично подходит для синхронизированных дисплеев, где одинаковая ширина предотвращает смещение элементов.

Уберите нули у секунд для более компактного отображения.

const shortDuration = { minutes: 5, seconds: 3 };

new Intl.DurationFormat('en', {
  style: 'digital',
  seconds: 'numeric'
}).format(shortDuration);
// "5:3"

Этот вариант встречается реже, потому что пользователи привыкли видеть секунды с ведущим нулём на цифровых дисплеях.

Добавление долей секунды в цифровой формат

Некоторым приложениям нужно показывать миллисекунды или микросекунды. Цифровой формат поддерживает доли секунды с помощью опции fractionalDigits.

Укажите, сколько знаков после запятой отображать после секунд.

const duration = {
  minutes: 5,
  seconds: 30,
  milliseconds: 123
};

new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 3
}).format(duration);
// "5:30.123"

Форматтер добавляет десятичную точку после секунд и показывает заданное количество дробных знаков.

Секундомеры обычно показывают сотые доли секунды.

const lap = {
  minutes: 1,
  seconds: 23,
  milliseconds: 450
};

new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 2
}).format(lap);
// "1:23.45"

Форматтер округляет до указанной точности. Значение 450 миллисекунд становится 45 сотыми.

Для микросекундной точности включите микросекунды в объект длительности и задайте больше дробных знаков.

const precise = {
  seconds: 42,
  milliseconds: 123,
  microseconds: 456
};

new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 6
}).format(precise);
// "42.123456"

Когда использовать цифровой формат, а когда другие стили

Выбирайте цифровой формат, если ваш интерфейс похож на таймер, секундомер или медиаплеер. В таких случаях пользователи ожидают именно этот формат.

Используйте цифровой формат для элементов управления видеоплеером.

function formatVideoTime(seconds) {
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const secs = Math.floor(seconds % 60);

  const duration = hours > 0
    ? { hours, minutes, seconds: secs }
    : { minutes, seconds: secs };

  return new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
}

formatVideoTime(6345); // "1:45:45"
formatVideoTime(125);  // "2:05"

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

function formatStopwatch(milliseconds) {
  const minutes = Math.floor(milliseconds / 60000);
  const seconds = Math.floor((milliseconds % 60000) / 1000);
  const ms = milliseconds % 1000;

  return new Intl.DurationFormat('en', {
    style: 'digital',
    fractionalDigits: 2
  }).format({ minutes, seconds, milliseconds: ms });
}

formatStopwatch(125450); // "2:05.45"

Используйте другие стили для отображения длительности в тексте или когда подписи делают интерфейс понятнее. На сайтах бронирования авиабилетов показывают «8 ч 15 мин» вместо «8:15:00», потому что это не таймер.

// Good for prose and descriptions
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 hr, 46 min and 40 sec"

// Good for timer displays
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "1:46:40"

Как вручную собрать цифровой формат для старых браузеров

API Intl.DurationFormat появилось в марте 2025 года. Для старых браузеров цифровой формат нужно собирать вручную.

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

function formatDigitalDuration(totalSeconds) {
  const hours = Math.floor(totalSeconds / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  const seconds = Math.floor(totalSeconds % 60);

  if (hours > 0) {
    const paddedMinutes = String(minutes).padStart(2, '0');
    const paddedSeconds = String(seconds).padStart(2, '0');
    return `${hours}:${paddedMinutes}:${paddedSeconds}`;
  } else {
    const paddedSeconds = String(seconds).padStart(2, '0');
    return `${minutes}:${paddedSeconds}`;
  }
}

formatDigitalDuration(6345); // "1:45:45"
formatDigitalDuration(125);  // "2:05"

Функция делит общее количество секунд на 3600, чтобы получить часы. Остаток делится на 60 — это минуты. Оставшееся — секунды.

Метод padStart() добавляет ведущие нули, если значение меньше 10. Это гарантирует, что «5» станет «05» для единообразного формата.

Если длительность хранится как объект duration, а не как общее количество секунд, извлекайте значения напрямую.

function formatDurationObject(duration) {
  const h = duration.hours || 0;
  const m = duration.minutes || 0;
  const s = duration.seconds || 0;

  if (h > 0) {
    return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
  }
  return `${m}:${String(s).padStart(2, '0')}`;
}

formatDurationObject({ hours: 1, minutes: 5, seconds: 30 }); // "1:05:30"
formatDurationObject({ minutes: 5, seconds: 30 }); // "5:30"

Добавьте доли секунды, включая миллисекунды и форматируя с десятичной точностью.

function formatWithMilliseconds(duration) {
  const m = duration.minutes || 0;
  const s = duration.seconds || 0;
  const ms = duration.milliseconds || 0;

  const paddedSeconds = String(s).padStart(2, '0');
  const fractional = String(ms).padStart(3, '0').slice(0, 2);

  return `${m}:${paddedSeconds}.${fractional}`;
}

formatWithMilliseconds({ minutes: 1, seconds: 23, milliseconds: 450 });
// "1:23.45"

Перед использованием проверьте поддержку API.

function formatDuration(duration) {
  if (typeof Intl.DurationFormat !== 'undefined') {
    return new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
  } else {
    return formatDurationObject(duration);
  }
}

Такой подход обеспечивает одинаковый результат во всех браузерах, используя нативный API, если он доступен.

Типовые шаблоны для видеоплееров и таймеров

Видеоплееры должны форматировать как текущее время, так и общую длительность. Создайте переиспользуемый форматтер для обоих значений.

const videoFormatter = new Intl.DurationFormat('en', { style: 'digital' });

function formatVideoPosition(currentSeconds, totalSeconds) {
  const current = secondsToDuration(currentSeconds);
  const total = secondsToDuration(totalSeconds);

  return `${videoFormatter.format(current)} / ${videoFormatter.format(total)}`;
}

function secondsToDuration(seconds) {
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const secs = Math.floor(seconds % 60);

  return hours > 0
    ? { hours, minutes, seconds: secs }
    : { minutes, seconds: secs };
}

formatVideoPosition(125, 6345); // "2:05 / 1:45:45"

Для таймеров обратного отсчёта, которые обновляются каждый кадр, создайте форматтер один раз и используйте повторно.

const timerFormatter = new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 2
});

function updateTimer(remainingMs) {
  const duration = {
    minutes: Math.floor(remainingMs / 60000),
    seconds: Math.floor((remainingMs % 60000) / 1000),
    milliseconds: remainingMs % 1000
  };

  document.getElementById('timer').textContent = timerFormatter.format(duration);
}

Для секундомеров с отображением кругов форматируйте прошедшее время с долями секунды.

const lapFormatter = new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 3
});

function formatLapTime(startMs, endMs) {
  const elapsedMs = endMs - startMs;

  return lapFormatter.format({
    minutes: Math.floor(elapsedMs / 60000),
    seconds: Math.floor((elapsedMs % 60000) / 1000),
    milliseconds: elapsedMs % 1000
  });
}

const lap1Start = performance.now();
// ... time passes ...
const lap1End = performance.now();

formatLapTime(lap1Start, lap1End); // "1:23.456"

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