基于Intl.RelativeTimeFormat实现双单位相对时间格式化函数
实现支持双时间单位的本地化相对时间函数
要实现支持两个时间单位的相对时间格式(如“2小时15分钟后”“1天6小时前”),同时保留Intl.RelativeTimeFormat的本地化能力,我们可以对原有函数做以下修改:
核心改动思路
- 不再只返回单个最大单位,而是提取最大有效单位和次一级有效单位,拼接两个本地化后的时间片段
- 修正时间单位计算逻辑,取整数部分而非四舍五入,避免出现“1天-2小时”这类不合理结果
- 统一处理未来/过去的时间差,无需拆分正负分支
- 处理边界情况:当次一级单位为0时仅返回单个单位;时间差为0时返回“刚刚”
修改后的完整代码
const fromNow = function (timestamp, locale = navigator.language) { const now = Date.now(); const diff = timestamp - now; const absDiff = Math.abs(diff); // 计算各时间单位的整数部分,保留正负符号 const days = Math.trunc(diff / (1000 * 60 * 60 * 24)); const hours = Math.trunc((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.trunc((diff % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.trunc((diff % (1000 * 60)) / 1000); const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'always' }); const parts = []; // 优先取最大的有效单位,再取次一级单位 if (absDiff >= 1000 * 60 * 60 * 24) { parts.push(rtf.format(days, 'day')); // 仅当小时数不为0时添加小时部分 if (Math.abs(hours) > 0) { parts.push(rtf.format(hours, 'hour').replace(/^[+-]?\d+ /, '')); } } else if (absDiff >= 1000 * 60 * 60) { parts.push(rtf.format(hours, 'hour')); if (Math.abs(minutes) > 0) { parts.push(rtf.format(minutes, 'minute').replace(/^[+-]?\d+ /, '')); } } else if (absDiff >= 1000 * 60) { parts.push(rtf.format(minutes, 'minute')); if (Math.abs(seconds) > 0) { parts.push(rtf.format(seconds, 'second').replace(/^[+-]?\d+ /, '')); } } else { // 小于1分钟时,仅显示秒数或"刚刚" return absDiff < 1000 ? '刚刚' : rtf.format(seconds, 'second'); } // 拼接结果,自动适配本地化格式 return parts.join(' '); }; export default fromNow;
关键细节说明
- 本地化支持:通过传入
locale参数(默认使用浏览器语言),Intl.RelativeTimeFormat会自动生成对应语言的相对时间描述(比如英文环境会返回"2 days 6 hours ago") - 单位处理:使用
Math.trunc取整数部分,确保时间单位为完整数值;拼接次一级单位时,通过正则去掉重复的正负前缀和数字,只保留单位描述(比如从"6 hours"提取"hours") - 边界处理:当时间差小于1秒时返回“刚刚”,避免显示“0秒后/前”这类不自然的描述;次一级单位为0时不显示,比如刚好2天则返回“2天后”而非“2天0小时后”
示例输出
- 未来2小时15分钟:
fromNow(Date.now() + 2*3600*1000 + 15*60*1000)→2小时15分钟后(中文环境) - 过去1天6小时:
fromNow(Date.now() - 24*3600*1000 - 6*3600*1000)→1天6小时前(中文环境) - 刚好3天:
fromNow(Date.now() + 3*24*3600*1000)→3天后(中文环境)
内容的提问来源于stack exchange,提问作者Julien Reszka
相关产品推荐
相关产品推荐

