如何将时长格式化为 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 样式
digital 样式会将时长格式化为数字时钟的样式。创建格式化器时,将 style 选项设置为 "digital"。
const formatter = new Intl.DurationFormat('en', { style: 'digital' });
只需传入包含所需时间单位的 duration 对象,格式化器会自动在各单位间添加冒号,并在需要时补零。
const duration = { hours: 1, minutes: 5, seconds: 30 };
formatter.format(duration);
// "1:05:30"
可以看到,分钟会显示为“05”而不是“5”。当存在小时数时,格式化器会自动将分钟补齐为两位数,这样在列表或表格中可以保持对齐。
如果时长没有小时,只需在 duration 对象中省略该属性即可。
const shortDuration = { minutes: 5, seconds: 30 };
formatter.format(shortDuration);
// "5:30"
当分钟是最大单位时,无需补零。这样格式既紧凑又清晰。
数字格式如何处理不同的时长
数字格式会根据 duration 对象中包含的时间单位调整输出。这与视频播放器根据视频长度自适应显示方式类似。
较短的时长只显示分钟和秒。
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 个百分之一秒。
如需微秒级精度,请在 duration 对象中包含微秒,并设置更高的小数位数。
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”,因为此场景不是计时器。
// Good for prose and descriptions
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 hr, 46 min and 40 sec"
// Good for timer displays
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”,以实现格式统一。
对于以 duration 对象而非总秒数存储的时长,请直接提取各个值。
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();
// ... time passes ...
const lap1End = performance.now();
formatLapTime(lap1Start, lap1End); // "1:23.456"
这些模式可处理最常见的时长格式化场景,同时保持代码简洁且易于复用。