如何将持续时间格式化为 2:30:45?
以带冒号的数字时钟格式显示时间持续时间
介绍
视频播放器、秒表和倒计时器以一种熟悉的格式显示时间。您看到 "2:30:45",会立即理解它表示 2 小时 30 分钟 45 秒。这种数字时钟格式使用冒号分隔时间单位,没有标签或空格。
手动构建这种格式需要用零填充数字并处理不同的时间长度。例如,一个运行 5 分钟 30 秒的视频显示为 "5:30",而一个 2 小时的视频显示为 "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')}`;
}
Intl.DurationFormat API 使用 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",因为上下文不是计时器。
// 适合散文和描述
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 小时, 46 分钟和 40 秒"
// 适合计时器显示
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "1:46:40"
为旧版浏览器手动构建数字格式
Intl.DurationFormat API 于 2025 年 3 月推出。对于旧版浏览器,可以手动构建数字格式。
手动方法需要从总秒数中计算时间单位,并用零填充值。
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",以实现一致的格式。
对于以持续时间对象而非总秒数存储的持续时间,可以直接提取值。
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();
// ... 时间流逝 ...
const lap1End = performance.now();
formatLapTime(lap1Start, lap1End); // "1:23.456"
这些模式处理了最常见的持续时间格式化场景,同时保持了代码的简洁和可重用性。