Intl.DurationFormat API
Format time durations in JavaScript with automatic localization
Introduction
When you display how long something takes, you need to format duration values for users. A video player shows runtime, a flight booking shows travel time, a fitness app shows workout duration. Without localization, you might write code like this:
const hours = 1;
const minutes = 46;
const seconds = 40;
const duration = `${hours}h ${minutes}m ${seconds}s`;
This produces "1h 46m 40s" for all users regardless of language. French users see "1h 46m 40s" when they expect "1 h 46 min 40 s". German users see the same English abbreviations. Spanish users get no "y" conjunction between units.
The Intl.DurationFormat API solves this. It formats time durations according to the user's language and cultural conventions without external libraries or manual string building.
const duration = { hours: 1, minutes: 46, seconds: 40 };
new Intl.DurationFormat('fr-FR', { style: 'short' }).format(duration);
// "1 h, 46 min et 40 s"
The formatter automatically handles abbreviations, conjunctions, word order, and spacing for any locale.
What are durations
A duration represents a span of time, not a point in time. Dates and times mark when something happens. Durations measure how long something takes.
This distinction matters for formatting. Dates involve calendars, timezones, and historical rules. Durations are simpler: they measure elapsed time in standard units without calendar context.
The Intl.DurationFormat API handles durations. The Intl.DateTimeFormat API handles dates and times. Use the right tool for each job.
Create a duration formatter
The constructor takes a locale and options object. The locale determines the output language. The options control formatting style and unit display.
const formatter = new Intl.DurationFormat('en', { style: 'long' });
Call format() with a duration object. The object contains numeric properties for time units. Only include the units you want to display.
const duration = { hours: 2, minutes: 30 };
formatter.format(duration);
// "2 hours and 30 minutes"
The API supports these time units: years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds. Use whichever units match your data.
Choose a formatting style
The style option controls output density. Four styles are available: long, short, narrow, and digital.
Long style uses full words. Use this for prose and accessibility.
const duration = { hours: 1, minutes: 46, seconds: 40 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "1 hour, 46 minutes and 40 seconds"
Short style uses common abbreviations. Use this when space is limited but readability matters.
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 hr, 46 min and 40 sec"
Narrow style uses minimal characters. Use this for compact displays like mobile interfaces.
new Intl.DurationFormat('en', { style: 'narrow' }).format(duration);
// "1h 46m 40s"
Digital style produces timer-like output with colons. Use this for media players and countdown displays.
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "1:46:40"
Localization across languages
The same duration formats differently in each language. The API handles all localization automatically.
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秒"
Notice how each locale uses different words, abbreviations, and conjunctions. French uses "et", German uses "und", Spanish uses "y", Japanese uses no conjunctions. The API knows these rules.
Short and narrow styles also localize correctly.
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."
Build duration objects from time calculations
Duration objects are plain JavaScript objects with time unit properties. Create them from any time calculation.
Convert milliseconds to duration units by dividing by the appropriate factors.
const milliseconds = 6400000; // 1 hour, 46 minutes, 40 seconds
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"
Calculate duration from two dates by subtracting 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 };
Include only the units you need. Omit zero values unless you want them displayed.
const duration = { minutes: 5, seconds: 30 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "5 minutes and 30 seconds"
Control which units appear
By default, the formatter shows all units you provide in the duration object. Control unit display with the options object.
Specify display style for each unit individually. Options are long, short, narrow, numeric, and 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"
The numeric style shows the number without labels. The 2-digit style adds zero-padding. Use these for compact displays mixing text and numbers.
Hide units by omitting them from both the duration object and options.
const duration = { hours: 2, minutes: 30 };
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "2 hr and 30 min"
Digital style requires all units from largest to smallest to be present or explicitly configured.
const duration = { minutes: 5, seconds: 30 };
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "5:30"
Format video player durations
Video players show duration in the controls. Use narrow or digital style for compact display.
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"
This handles both short and long videos by conditionally including hours.
Format flight and travel times
Travel booking interfaces show journey duration. Use short style for readability in limited space.
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"
Format workout and activity durations
Fitness apps track exercise duration. Use long style for session summaries and narrow style for list views.
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"
Get formatted parts for custom display
The formatToParts() method returns an array of objects representing each piece of the formatted output. Use this to style individual parts or build custom layouts.
const duration = { hours: 1, minutes: 46, seconds: 40 };
const parts = new Intl.DurationFormat('en', { style: 'long' }).formatToParts(duration);
Each part has a type and value. Types include hour, minute, second, literal, and unit labels like 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" }
]
Map over parts to apply custom styling.
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>;
});
}
Reuse formatter instances for performance
Creating a new formatter for each duration adds overhead. Create the formatter once and reuse it.
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"]
This pattern improves performance when formatting many durations in loops or renders.
Migrate from manual string building
Replace manual string concatenation with the API. This reduces code and adds localization.
Before:
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`;
}
}
After:
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);
}
The API version handles all the conditional logic automatically and supports multiple languages.
Migrate from libraries
Libraries like Moment.js and date-fns provide duration formatting but add bundle size. The native API eliminates this dependency.
Replace Moment.js duration formatting:
// Before: Moment.js
const duration = moment.duration(6400, 'seconds');
const formatted = duration.hours() + 'h ' + duration.minutes() + 'm';
// After: Intl.DurationFormat
const duration = {
hours: Math.floor(6400 / 3600),
minutes: Math.floor((6400 % 3600) / 60)
};
new Intl.DurationFormat('en', { style: 'narrow' }).format(duration);
Replace date-fns duration formatting:
// Before: date-fns
import { formatDuration, intervalToDuration } from 'date-fns';
const duration = intervalToDuration({ start: 0, end: 6400000 });
const formatted = formatDuration(duration);
// After: 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);
The native API provides the same functionality with no dependencies.
Browser support and polyfills
The Intl.DurationFormat API became Baseline in March 2025. It works in the latest versions of Chrome, Edge, Firefox, and Safari.
Check support before using:
if (typeof Intl.DurationFormat !== 'undefined') {
const formatter = new Intl.DurationFormat('en', { style: 'short' });
return formatter.format(duration);
} else {
// Fallback for older browsers
return `${duration.hours}h ${duration.minutes}m`;
}
For broader support, use a polyfill. The FormatJS project provides @formatjs/intl-durationformat.
npm install @formatjs/intl-durationformat
Import and polyfill if needed:
if (!Intl.DurationFormat) {
await import('@formatjs/intl-durationformat/polyfill');
}
The polyfill adds about 15KB gzipped. Load it conditionally to avoid overhead for modern browsers.
When to use DurationFormat
Use Intl.DurationFormat when displaying elapsed time, time remaining, or duration measurements. This includes video players, timers, countdowns, tracking apps, travel bookings, and session duration displays.
Do not use it for dates, times, or timestamps. Use Intl.DateTimeFormat for those. Do not use it for relative time expressions like "2 hours ago". Use Intl.RelativeTimeFormat for those.
The API formats durations, not time calculations. You must calculate the duration values yourself from dates, timestamps, or other sources. The formatter only handles display.