API Intl.DurationFormat
Formatea duraciones de tiempo en JavaScript con localización automática
Introducción
Cuando muestras cuánto tiempo toma algo, necesitas formatear los valores de duración para los usuarios. Un reproductor de video muestra el tiempo de reproducción, una reserva de vuelo muestra el tiempo de viaje, una aplicación de fitness muestra la duración del entrenamiento. Sin localización, podrías escribir código como este:
const hours = 1;
const minutes = 46;
const seconds = 40;
const duration = `${hours}h ${minutes}m ${seconds}s`;
Esto produce "1h 46m 40s" para todos los usuarios independientemente del idioma. Los usuarios franceses ven "1h 46m 40s" cuando esperan "1 h 46 min 40 s". Los usuarios alemanes ven las mismas abreviaturas en inglés. Los usuarios españoles no obtienen la conjunción "y" entre unidades.
La API Intl.DurationFormat resuelve esto. Formatea las duraciones de tiempo según el idioma y las convenciones culturales del usuario sin bibliotecas externas ni construcción manual de cadenas.
const duration = { hours: 1, minutes: 46, seconds: 40 };
new Intl.DurationFormat('fr-FR', { style: 'short' }).format(duration);
// "1 h, 46 min et 40 s"
El formateador maneja automáticamente abreviaturas, conjunciones, orden de palabras y espaciado para cualquier configuración regional.
Qué son las duraciones
Una duración representa un lapso de tiempo, no un punto en el tiempo. Las fechas y horas marcan cuándo sucede algo. Las duraciones miden cuánto tiempo toma algo.
Esta distinción es importante para el formateo. Las fechas involucran calendarios, zonas horarias y reglas históricas. Las duraciones son más simples: miden el tiempo transcurrido en unidades estándar sin contexto de calendario.
La API Intl.DurationFormat maneja duraciones. La API Intl.DateTimeFormat maneja fechas y horas. Usa la herramienta adecuada para cada trabajo.
Crear un formateador de duración
El constructor toma un locale y un objeto de opciones. El locale determina el idioma de salida. Las opciones controlan el estilo de formateo y la visualización de unidades.
const formatter = new Intl.DurationFormat('en', { style: 'long' });
Llama a format() con un objeto de duración. El objeto contiene propiedades numéricas para unidades de tiempo. Solo incluye las unidades que quieres mostrar.
const duration = { hours: 2, minutes: 30 };
formatter.format(duration);
// "2 hours and 30 minutes"
La API admite estas unidades de tiempo: years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds. Utiliza las unidades que coincidan con tus datos.
Elige un estilo de formato
La opción style controla la densidad de la salida. Hay cuatro estilos disponibles: long, short, narrow y digital.
El estilo largo utiliza palabras completas. Úsalo para prosa y accesibilidad.
const duration = { hours: 1, minutes: 46, seconds: 40 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "1 hour, 46 minutes and 40 seconds"
El estilo corto utiliza abreviaturas comunes. Úsalo cuando el espacio es limitado pero la legibilidad importa.
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 hr, 46 min and 40 sec"
El estilo estrecho utiliza caracteres mínimos. Úsalo para visualizaciones compactas como interfaces móviles.
new Intl.DurationFormat('en', { style: 'narrow' }).format(duration);
// "1h 46m 40s"
El estilo digital produce una salida similar a un temporizador con dos puntos. Úsalo para reproductores multimedia y visualizaciones de cuenta regresiva.
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "1:46:40"
Localización en diferentes idiomas
La misma duración se formatea de manera diferente en cada idioma. La API maneja toda la localización automáticamente.
const duration = { hours: 1, minutes: 46, seconds: 40 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "1 hour, 46 minutes and 40 seconds"
new Intl.DurationFormat('fr', { style: 'long' }).format(duration);
// "1 heure, 46 minutes et 40 secondes"
new Intl.DurationFormat('de', { style: 'long' }).format(duration);
// "1 Stunde, 46 Minuten und 40 Sekunden"
new Intl.DurationFormat('es', { style: 'long' }).format(duration);
// "1 hora, 46 minutos y 40 segundos"
new Intl.DurationFormat('ja', { style: 'long' }).format(duration);
// "1時間46分40秒"
Observa cómo cada localización utiliza diferentes palabras, abreviaturas y conjunciones. El francés usa "et", el alemán usa "und", el español usa "y", el japonés no usa conjunciones. La API conoce estas reglas.
Los estilos corto y estrecho también se localizan correctamente.
new Intl.DurationFormat('fr', { style: 'short' }).format(duration);
// "1 h, 46 min et 40 s"
new Intl.DurationFormat('de', { style: 'narrow' }).format(duration);
// "1 Std. 46 Min. 40 Sek."
Construir objetos de duración a partir de cálculos de tiempo
Los objetos de duración son objetos JavaScript simples con propiedades de unidades de tiempo. Créalos a partir de cualquier cálculo de tiempo.
Convierte milisegundos a unidades de duración dividiéndolos por los factores apropiados.
const milliseconds = 6400000; // 1 hora, 46 minutos, 40 segundos
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: 'short' }).format(duration);
// "1 hr, 46 min and 40 sec"
Calcula la duración entre dos fechas restando timestamps.
const start = new Date('2025-01-01T10:00:00');
const end = new Date('2025-01-01T11:46:40');
const diffMs = end - start;
const hours = Math.floor(diffMs / 3600000);
const minutes = Math.floor((diffMs % 3600000) / 60000);
const seconds = Math.floor((diffMs % 60000) / 1000);
const duration = { hours, minutes, seconds };
Incluye solo las unidades que necesites. Omite los valores cero a menos que quieras mostrarlos.
const duration = { minutes: 5, seconds: 30 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "5 minutes and 30 seconds"
Controla qué unidades aparecen
Por defecto, el formateador muestra todas las unidades que proporcionas en el objeto de duración. Controla la visualización de unidades con el objeto de opciones.
Especifica el estilo de visualización para cada unidad individualmente. Las opciones son long, short, narrow, numeric y 2-digit.
const duration = { hours: 1, minutes: 5, seconds: 3 };
new Intl.DurationFormat('en', {
hours: 'long',
minutes: 'numeric',
seconds: '2-digit'
}).format(duration);
// "1 hour, 5:03"
El estilo numeric muestra el número sin etiquetas. El estilo 2-digit añade relleno de ceros. Úsalos para visualizaciones compactas que mezclan texto y números.
Oculta unidades omitiéndolas tanto del objeto de duración como de las opciones.
const duration = { hours: 2, minutes: 30 };
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "2 hr and 30 min"
El estilo digital requiere que todas las unidades desde la más grande hasta la más pequeña estén presentes o explícitamente configuradas.
const duration = { minutes: 5, seconds: 30 };
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "5:30"
Formatear duraciones del reproductor de video
Los reproductores de video muestran la duración en los controles. Utiliza el estilo estrecho o digital para una visualización compacta.
function formatVideoDuration(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 };
const locale = navigator.language;
return new Intl.DurationFormat(locale, { style: 'digital' }).format(duration);
}
formatVideoDuration(6400); // "1:46:40"
formatVideoDuration(330); // "5:30"
Esto maneja videos tanto cortos como largos incluyendo las horas condicionalmente.
Formatear tiempos de vuelo y viaje
Las interfaces de reserva de viajes muestran la duración del trayecto. Utiliza el estilo corto para mejorar la legibilidad en espacios limitados.
function formatFlightDuration(departureDate, arrivalDate, locale) {
const diffMs = arrivalDate - departureDate;
const hours = Math.floor(diffMs / 3600000);
const minutes = Math.floor((diffMs % 3600000) / 60000);
const duration = { hours, minutes };
return new Intl.DurationFormat(locale, { style: 'short' }).format(duration);
}
const departure = new Date('2025-06-15T10:30:00');
const arrival = new Date('2025-06-15T18:45:00');
formatFlightDuration(departure, arrival, 'en');
// "8 hr and 15 min"
formatFlightDuration(departure, arrival, 'fr');
// "8 h et 15 min"
Formatear duraciones de entrenamientos y actividades
Las aplicaciones de fitness registran la duración del ejercicio. Utiliza el estilo largo para resúmenes de sesiones y el estilo estrecho para vistas de lista.
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-06-15T07:00:00');
const workoutEnd = new Date('2025-06-15T08:15:00');
formatWorkoutDuration(workoutStart, workoutEnd, 'en');
// "1 hour and 15 minutes"
Obtener partes formateadas para visualización personalizada
El método formatToParts() devuelve un array de objetos que representan cada parte de la salida formateada. Utiliza esto para aplicar estilos a partes individuales o crear diseños personalizados.
const duration = { hours: 1, minutes: 46, seconds: 40 };
const parts = new Intl.DurationFormat('en', { style: 'long' }).formatToParts(duration);
Cada parte tiene un type y un value. Los tipos incluyen hour, minute, second, literal, y etiquetas de unidad como hourUnit, minuteUnit.
[
{ type: "integer", value: "1" },
{ type: "literal", value: " " },
{ type: "unit", value: "hour" },
{ type: "literal", value: ", " },
{ type: "integer", value: "46" },
{ type: "literal", value: " " },
{ type: "unit", value: "minutes" },
{ type: "literal", value: " and " },
{ type: "integer", value: "40" },
{ type: "literal", value: " " },
{ type: "unit", value: "seconds" }
]
Recorre las partes para aplicar estilos personalizados.
function StyledDuration({ duration }) {
const parts = new Intl.DurationFormat('en', { style: 'long' }).formatToParts(duration);
return parts.map((part, i) => {
if (part.type === 'integer') {
return <strong key={i}>{part.value}</strong>;
}
return <span key={i}>{part.value}</span>;
});
}
Reutilizar instancias del formateador para mejorar el rendimiento
Crear un nuevo formateador para cada duración añade sobrecarga. Crea el formateador una vez y reutilízalo.
const formatter = new Intl.DurationFormat('en', { style: 'short' });
const durations = [
{ hours: 1, minutes: 30 },
{ hours: 2, minutes: 15 },
{ hours: 0, minutes: 45 }
];
durations.map(d => formatter.format(d));
// ["1 hr and 30 min", "2 hr and 15 min", "45 min"]
Este patrón mejora el rendimiento cuando se formatean muchas duraciones en bucles o renderizados.
Migrar desde la construcción manual de cadenas
Reemplaza la concatenación manual de cadenas con la API. Esto reduce el código y añade localización.
Antes:
function formatDuration(hours, minutes) {
if (hours > 0 && minutes > 0) {
return `${hours}h ${minutes}m`;
} else if (hours > 0) {
return `${hours}h`;
} else {
return `${minutes}m`;
}
}
Después:
function formatDuration(hours, minutes, locale) {
const duration = {};
if (hours > 0) duration.hours = hours;
if (minutes > 0) duration.minutes = minutes;
return new Intl.DurationFormat(locale, { style: 'narrow' }).format(duration);
}
La versión de la API maneja toda la lógica condicional automáticamente y soporta múltiples idiomas.
Migrar desde bibliotecas
Bibliotecas como Moment.js y date-fns proporcionan formato de duración pero aumentan el tamaño del paquete. La API nativa elimina esta dependencia.
Reemplazar el formato de duración de Moment.js:
// Antes: Moment.js
const duration = moment.duration(6400, 'seconds');
const formatted = duration.hours() + 'h ' + duration.minutes() + 'm';
// Después: Intl.DurationFormat
const duration = {
hours: Math.floor(6400 / 3600),
minutes: Math.floor((6400 % 3600) / 60)
};
new Intl.DurationFormat('en', { style: 'narrow' }).format(duration);
Reemplazar el formato de duración de date-fns:
// Antes: date-fns
import { formatDuration, intervalToDuration } from 'date-fns';
const duration = intervalToDuration({ start: 0, end: 6400000 });
const formatted = formatDuration(duration);
// Después: Intl.DurationFormat
const ms = 6400000;
const duration = {
hours: Math.floor(ms / 3600000),
minutes: Math.floor((ms % 3600000) / 60000),
seconds: Math.floor((ms % 60000) / 1000)
};
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
La API nativa proporciona la misma funcionalidad sin dependencias.
Soporte de navegadores y polyfills
La API Intl.DurationFormat se convirtió en Baseline en marzo de 2025. Funciona en las últimas versiones de Chrome, Edge, Firefox y Safari.
Verifica el soporte antes de usar:
if (typeof Intl.DurationFormat !== 'undefined') {
const formatter = new Intl.DurationFormat('en', { style: 'short' });
return formatter.format(duration);
} else {
// Alternativa para navegadores antiguos
return `${duration.hours}h ${duration.minutes}m`;
}
Para un soporte más amplio, utiliza un polyfill. El proyecto FormatJS proporciona @formatjs/intl-durationformat.
npm install @formatjs/intl-durationformat
Importa y aplica el polyfill si es necesario:
if (!Intl.DurationFormat) {
await import('@formatjs/intl-durationformat/polyfill');
}
El polyfill añade aproximadamente 15KB comprimido. Cárgalo condicionalmente para evitar sobrecarga en navegadores modernos.
Cuándo usar DurationFormat
Utiliza Intl.DurationFormat cuando muestres tiempo transcurrido, tiempo restante o mediciones de duración. Esto incluye reproductores de video, temporizadores, cuentas regresivas, aplicaciones de seguimiento, reservas de viajes y visualizaciones de duración de sesiones.
No lo uses para fechas, horas o marcas de tiempo. Utiliza Intl.DateTimeFormat para esos casos. No lo uses para expresiones de tiempo relativo como "hace 2 horas". Utiliza Intl.RelativeTimeFormat para esos casos.
La API formatea duraciones, no realiza cálculos de tiempo. Debes calcular tú mismo los valores de duración a partir de fechas, marcas de tiempo u otras fuentes. El formateador solo se encarga de la visualización.