¿Cómo formateo duraciones como 2:30:45?

Mostrar duraciones de tiempo en formato de reloj digital con dos puntos

Introducción

Los reproductores de video, cronómetros y temporizadores de cuenta regresiva muestran duraciones en un formato familiar. Ves "2:30:45" y entiendes inmediatamente que significa 2 horas, 30 minutos y 45 segundos. Este formato de reloj digital utiliza dos puntos para separar las unidades de tiempo sin etiquetas ni espacios.

Crear este formato manualmente requiere rellenar números con ceros y manejar diferentes longitudes de duración. Un video que dura 5 minutos y 30 segundos muestra "5:30" mientras que un video de 2 horas muestra "2:00:00". La lógica se vuelve compleja con casos especiales.

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')}`;
}

La API Intl.DurationFormat maneja esto automáticamente con la opción de estilo digital. Produce el formato correcto para cualquier longitud de duración.

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

Usar estilo digital para visualizaciones de temporizadores

El estilo digital formatea duraciones como un reloj digital. Establece la opción style a "digital" cuando crees el formateador.

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

Pasa un objeto de duración con las unidades de tiempo que quieres mostrar. El formateador añade dos puntos entre unidades y rellena valores con ceros donde sea necesario.

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

Observa cómo los minutos se muestran como "05" en lugar de "5". El formateador automáticamente rellena los minutos a dos dígitos cuando hay horas presentes. Esto mantiene la alineación en listas y tablas.

Para duraciones sin horas, omite esa propiedad del objeto de duración.

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

Los minutos ya no necesitan relleno cuando son la unidad más grande. El formato se mantiene compacto pero claro.

Cómo el formato digital maneja diferentes longitudes de duración

El formato digital ajusta la salida según las unidades que incluyas en el objeto de duración. Esto coincide con la forma en que los reproductores de video adaptan su visualización a la longitud del video.

Una duración corta muestra solo minutos y segundos.

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

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

Una duración más larga incluye horas.

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

Cuando aparecen las horas, todas las unidades menores se rellenan a dos dígitos. Cuando las horas están ausentes, los minutos se muestran sin relleno pero los segundos siguen rellenándose.

Esta regla de relleno crea una alineación consistente sin desperdiciar espacio. Una lista de videos cortos muestra "5:30", "12:45", "8:02" con los dos puntos alineados. Una lista de videos largos muestra "1:05:30", "2:12:45", "3:08:02" con un formato consistente.

Incluye solo las unidades que tu interfaz necesita. Un temporizador de cuenta regresiva que nunca excede una hora puede omitir las horas por completo.

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

Controla el relleno de ceros y las opciones de visualización

El formato digital utiliza reglas de relleno predeterminadas, pero puedes anularlas especificando opciones para unidades de tiempo individuales.

Controla cómo se muestra cada unidad configurando opciones específicas para cada unidad. El valor numeric muestra el número sin relleno. El valor 2-digit fuerza el relleno de dos dígitos.

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"

Este es el comportamiento predeterminado. Solo necesitas especificar estas opciones cuando deseas un formato diferente.

Fuerza que las horas siempre muestren dos dígitos.

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

Este formato funciona bien para visualizaciones sincronizadas donde el ancho consistente evita cambios en el diseño.

Elimina el relleno de los segundos para una visualización más compacta.

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

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

Este formato es menos común porque los usuarios esperan que los segundos se rellenen en visualizaciones digitales.

Añadir segundos fraccionarios al formato digital

Algunas aplicaciones necesitan mostrar milisegundos o microsegundos. El formato digital admite segundos fraccionarios con la opción fractionalDigits.

Establece cuántos decimales mostrar después de los segundos.

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

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

El formateador añade un punto decimal después de los segundos y muestra el número especificado de dígitos fraccionarios.

Los cronómetros normalmente muestran centésimas de segundo.

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

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

El formateador redondea a la precisión especificada. El valor de 450 milisegundos se convierte en 45 centésimas.

Para precisión de microsegundos, incluye microsegundos en el objeto de duración y establece más dígitos fraccionarios.

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

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

Cuándo usar formato digital frente a otros estilos

Elige el formato digital cuando tu interfaz se asemeje a un temporizador, cronómetro o reproductor multimedia. Los usuarios esperan este formato en estos contextos.

Utiliza el formato digital para los controles del reproductor de vídeo.

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"

Utiliza el formato digital para temporizadores de cuenta atrás y cronómetros.

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"

Utiliza otros estilos cuando muestres duraciones en prosa o cuando las etiquetas mejoren la claridad. Los sitios de reserva de vuelos muestran "8 h 15 min" en lugar de "8:15:00" porque el contexto no es un temporizador.

// Bueno para prosa y descripciones
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 hr, 46 min and 40 sec"

// Bueno para visualizaciones de temporizador
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "1:46:40"

Construir formato digital manualmente para navegadores antiguos

La API Intl.DurationFormat estará disponible en marzo de 2025. Para navegadores más antiguos, construye el formato digital manualmente.

El enfoque manual requiere calcular unidades de tiempo a partir de segundos totales y rellenar valores con ceros.

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"

La función divide los segundos totales por 3600 para obtener las horas. El resto dividido por 60 da los minutos. El resto final son los segundos.

El método padStart() añade ceros a la izquierda cuando el valor es menor que 10. Esto asegura que "5" se convierta en "05" para un formato consistente.

Para duraciones almacenadas como objetos de duración en lugar de segundos totales, extrae los valores directamente.

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"

Añade segundos fraccionarios incluyendo milisegundos y formateando con precisión decimal.

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"

Verifica el soporte de la API antes de usarla.

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

Este enfoque proporciona una salida consistente en todos los navegadores mientras utiliza la API nativa cuando está disponible.

Patrones comunes para reproductores de video y temporizadores

Los reproductores de video necesitan formatear tanto el tiempo actual como la duración total. Crea un formateador reutilizable para manejar ambos valores.

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"

Para temporizadores de cuenta regresiva que se actualizan en cada fotograma, crea el formateador una vez y reutilízalo.

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);
}

Para cronómetros que muestran tiempos de vuelta, formatea el tiempo transcurrido con segundos fraccionarios.

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();
// ... tiempo transcurrido ...
const lap1End = performance.now();

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

Estos patrones manejan los escenarios más comunes de formateo de duración mientras mantienen un código limpio y reutilizable.