Why Native Duration Formatting Matters
Before Intl.DurationFormat, developers had two choices: write custom formatting logic that manually handles pluralization, separators, and locale-specific patterns, or import external libraries like Moment.js or date-fns. Both approaches added complexity and bundle size to applications.
The native Intl.DurationFormat API eliminates these concerns by providing browser-optimized, locale-aware duration formatting out of the box. Since reaching Baseline status in March 2025, it's supported across all major browsers, making it production-ready for modern web applications.
Implementing proper localization contributes to better SEO performance by improving user experience for international audiences and reducing bounce rates from frustrated users who encounter poorly formatted time displays.
Browser Support Status
- Chrome: Full support since version 133+
- Firefox: Full support since version 134+
- Safari: Full support since version 17+
- Edge: Full support since matching Chromium version
For legacy browser support, the FormatJS polyfill provides compatibility while you transition.
1const duration = {2 hours: 2,3 minutes: 30,4 seconds: 455};6 7// Default formatting (short style)8new Intl.DurationFormat('en-US').format(duration);9// "2 hr, 30 min and 45 sec"10 11// Long style for accessibility12new Intl.DurationFormat('en-US', { style: 'long' }).format(duration);13// "2 hours, 30 minutes and 45 seconds"14 15// Narrow style for compact spaces16new Intl.DurationFormat('en-US', { style: 'narrow' }).format(duration);17// "2h 30m 45s"Core Concepts: Duration Objects
The Intl.DurationFormat API works with plain JavaScript objects that represent durations. Each time unit is optional--you only need to include the units relevant to your use case.
Duration Object Structure
const duration = {
years: 1,
months: 3,
weeks: 2,
days: 5,
hours: 20,
minutes: 45,
seconds: 30,
milliseconds: 123,
microseconds: 456,
nanoseconds: 789
};
The API automatically omits units with zero values and formats only the units you provide. This makes it flexible for everything from displaying video timestamps to showing project timelines. For teams building AI-powered applications, this native formatting integrates seamlessly with modern JavaScript ecosystems.
Constructor Parameters
The Intl.DurationFormat constructor accepts two parameters:
- locales: A string or array of locale identifiers (e.g.,
'en-US',['fr-FR', 'de-DE']) - options: Configuration object for styling and display preferences
Style Options
The style option controls the verbosity of the formatted output. Choose based on your UI constraints and accessibility requirements.
Style Comparison
| Style | Example Output | Use Case |
|---|---|---|
short | "1 hr, 30 min" | Standard interfaces |
long | "1 hour, 30 minutes" | Accessibility, formal contexts |
narrow | "1h 30m" | Space-constrained UIs |
Display Unit Selection
You can also specify which units to include in the output:
new Intl.DurationFormat('en-US', {
style: 'long',
hours: 'numeric',
minutes: 'numeric',
seconds: 'numeric'
}).format({ hours: 2, minutes: 30 });
// "2 hours and 30 minutes"
Method Reference
format() -- Simple String Output
The format() method is your go-to for most use cases. It returns a fully formatted duration string ready for display.
const duration = { hours: 1, minutes: 46, seconds: 40 };
const formatter = new Intl.DurationFormat('fr-FR', { style: 'long' });
formatter.format(duration);
// "1 heure, 46 minutes et 40 secondes"
formatToParts() -- Structured Output
When you need fine-grained control over styling, formatToParts() returns an array of objects describing each part of the formatted string.
const duration = { hours: 1, minutes: 30 };
const formatter = new Intl.DurationFormat('en-US');
formatter.formatToParts(duration);
// [
// { type: 'integer', value: '1', unit: 'hour' },
// { type: 'literal', value: ' ', unit: 'hour' },
// { type: 'unit', value: 'hr', unit: 'hour' },
// { type: 'literal', value: ', ', unit: 'minute' },
// { type: 'integer', value: '30', unit: 'minute' },
// { type: 'literal', value: ' ', unit: 'minute' },
// { type: 'unit', value: 'min', unit: 'minute' }
// ]
resolvedOptions() -- Configuration Discovery
Returns the effective options after locale negotiation, useful for debugging.
const formatter = new Intl.DurationFormat('en-US', { style: 'short' });
formatter.resolvedOptions();
// { locale: 'en-US', style: 'short', ... }
Internationalization in Practice
The real power of Intl.DurationFormat is its automatic handling of locale-specific conventions. Different languages have different rules for pluralization, conjunction, and unit formatting. This built-in internationalization capability saves hours of development time.
Multi-Locale Examples
const duration = { hours: 1, minutes: 46, seconds: 40 };
// English (US)
new Intl.DurationFormat('en-US', { style: 'long' }).format(duration);
// "1 hour, 46 minutes and 40 seconds"
// French
new Intl.DurationFormat('fr-FR', { style: 'long' }).format(duration);
// "1 heure, 46 minutes et 40 secondes"
// German
new Intl.DurationFormat('de-DE', { style: 'long' }).format(duration);
// "1 Stunde, 46 Minuten und 40 Sekunden"
// Japanese
new Intl.DurationFormat('ja-JP', { style: 'long' }).format(duration);
// "1 時間 46 分 40 秒"
// Norwegian
new Intl.DurationFormat('no', { style: 'long' }).format(duration);
// "1 år, 20 timer, 15 minutter og 35 sekunder"
// Swahili
new Intl.DurationFormat('sw', { style: 'long' }).format(duration);
// "saa 1, dakika 46 na sekunde 40"
Automatic Language Features
- Pluralization: Automatically handles languages with complex plural rules (Slavic, Arabic)
- Conjunctions: Respects locale-specific conjunction patterns (English "and" vs. other separators)
- Unit Names: Uses correct localized unit terminology
- Direction: Respects RTL text direction for languages like Arabic and Hebrew
Performance and Optimization
Efficient Formatter Reuse
Creating an Intl.DurationFormat instance has overhead. Reuse instances across your application for optimal performance. This pattern is especially important in high-traffic web applications where every millisecond counts.
// ❌ Avoid: Creating formatter on every call
function formatDuration(duration) {
const formatter = new Intl.DurationFormat('en-US');
return formatter.format(duration);
}
// ✅ Better: Reuse formatter instance
const durationFormatter = new Intl.DurationFormat('en-US', {
style: 'long'
});
function formatDuration(duration) {
return durationFormatter.format(duration);
}
Bundle Size Comparison
| Solution | Bundle Size (gzip) | Format Speed |
|---|---|---|
| Intl.DurationFormat | ~0KB (native) | Fastest |
| Moment.js | ~70KB | Slower |
| date-fns | ~15KB | Moderate |
Performance Tips
- Create formatters at module level or with memoization
- Cache formatters by locale/configuration combination
- Use
formatToParts()sparingly--it's slower thanformat() - For high-frequency updates (video progress), create formatter once and reuse
Explore more web development resources for performance optimization techniques.
1'use client';2 3import { useMemo } from 'react';4 5interface DurationDisplayProps {6 hours: number;7 minutes: number;8 seconds: number;9 locale?: string;10}11 12export function DurationDisplay({13 hours,14 minutes,15 seconds,16 locale = 'en-US'17}: DurationDisplayProps) {18 const formatter = useMemo(() => {19 return new Intl.DurationFormat(locale, {20 style: 'long',21 hours: 'numeric',22 minutes: 'numeric',23 seconds: 'numeric'24 });25 }, [locale]);26 27 const formatted = formatter.format({ hours, minutes, seconds });28 29 return <span className="duration-display">{formatted}</span>;30}Best Practices and Common Patterns
Recommended Configuration Patterns
Video Player Time Display
const videoTimeFormatter = new Intl.DurationFormat('en-US', {
style: 'short',
hours: 'numeric',
minutes: 'numeric',
seconds: 'numeric'
});
Progress/Elapsed Time
const progressFormatter = new Intl.DurationFormat('en-US', {
style: 'narrow',
hours: 'numeric',
minutes: 'numeric'
});
Accessibility-Focused Display
const accessibleFormatter = new Intl.DurationFormat('en-US', {
style: 'long',
hours: 'numeric',
minutes: 'numeric',
seconds: 'numeric'
});
Feature Detection Pattern
function supportsDurationFormat() {
try {
new Intl.DurationFormat('en-US');
return true;
} catch {
return false;
}
}