Intl.RelativeTimeFormat用于将时间差转为自然语言描述,需手动计算毫秒差并换算单位后传入,不自动刷新,须配合定时器实现动态更新。

Intl.RelativeTimeFormat 可以把时间差转成自然语言(如“2分钟前”“昨天”),但它本身不自动刷新——要实现“动态更新”的效果,得配合定时器手动触发格式化。
一、基础用法:把时间差转成中文相对描述
先创建一个格式化器实例,指定语言和地区:
const rtf = new Intl.RelativeTimeFormat('zh-CN', {
numeric: 'always',
style: 'short'
});然后传入数值和单位(注意:单位必须是字符串,且为单数形式):
rtf.format(-2, 'minute'); // → "2分钟前" rtf.format(1, 'day'); // → "明天" rtf.format(-1, 'hour'); // → "1小时前"
二、计算当前与目标时间的相对差值
不能直接传入 Date 对象,需先算出毫秒差,再换算成年/月/日/小时/分钟等单位。推荐按从大到小顺序判断,选最合适的粒度:
- 如果差值 秒
- 60 秒 ≤ 差值 分钟
- 3600 秒 ≤ 差值 小时
- 86400 秒 ≤ 差值 天
- 超过约30天 → 可退回到 年/月,或改用绝对日期(如“2024/05/10”)
示例函数:
function getTimeAgo(date) {
const now = Date.now();
const diffMs = now - date.getTime();
const diffSec = Math.floor(diffMs / 1000);
const diffMin = Math.floor(diffSec / 60);
const diffHour = Math.floor(diffMin / 60);
const diffDay = Math.floor(diffHour / 24);
<p>if (diffSec </p>三、实现动态更新:定时重渲染
“刚才”会变成“1秒前”“2秒前”……需要每秒或每分钟重新调用 getTimeAgo() 并更新 DOM。常见做法:
- 对每个时间标签单独启动
setInterval(适合少量条目) - 统一用一个
requestAnimationFrame或每秒一次的setInterval批量更新所有活跃标签(更高效) - 只在标签进入视口时开始计时,离开时暂停(可用 IntersectionObserver 优化性能)
简易批量更新示例:
const timeElements = document.querySelectorAll('[data-timestamp]');
let timer;
<p>function updateAllTimes() {
timeElements.forEach(el => {
const ts = parseInt(el.dataset.timestamp, 10);
el.textContent = getTimeAgo(new Date(ts));
});
}</p><p>// 每秒更新一次
timer = setInterval(updateAllTimes, 1000);
updateAllTimes(); // 立即执行一次</p>四、注意事项与优化建议
-
避免高频重排:不要用 innerHTML 替换整个节点,优先用
textContent -
处理时区:确保传入的 Date 对象已按用户本地时区解析(后端通常发 ISO 时间字符串,
new Date(isoStr)会自动转成本地时间) -
“刚刚”的临界点:Intl 不提供“刚刚”,可在 diffSec ≤ 3 时硬编码返回
"刚刚" - 服务端预渲染兼容:首次渲染由服务端输出静态时间(如“2分钟前”),再由前端接管后续更新
- 国际化扩展:可按 navigator.language 初始化 rtf,或根据用户设置切换
不复杂但容易忽略细节,核心就三点:正确算差值、合理选单位、定时触发更新。










