用原生JS Date复刻moment.js的fromNow函数,结果差一天如何解决?
问题:原生JS复刻moment.js fromNow函数时日期差一天的问题
你遇到的核心问题有两个:一是Unix时间戳的单位转换错误,二是多余的时区偏移处理导致时间差计算错误。
错误分析
- 时间戳单位错误:
Date构造函数接收的数字参数是毫秒级Unix时间戳,但你的函数传入的是秒级时间戳,直接创建new Date(targetUnixTimestampInSeconds)会导致目标日期被错误解析。 - 时区偏移处理错误:Unix时间戳本身是基于UTC的,
now.getTime()和targetDate.getTime()返回的都是UTC毫秒数,计算时间差时不需要额外添加时区偏移,你的代码中+ targetOffsetInSeconds会让目标时间的秒数变大,最终导致计算出的时间差偏小,少算一天。
修正后的函数
const fromNow = targetUnixTimestampInSeconds => { const now = new Date(); const nowInSeconds = Math.floor(now.getTime() / 1000); // 正确将秒级时间戳转为Date对象(乘以1000转毫秒) const targetDate = new Date(targetUnixTimestampInSeconds * 1000); // 直接获取UTC秒数,无需时区偏移 const targetInSeconds = Math.floor(targetDate.getTime() / 1000); const diffInSeconds = nowInSeconds - targetInSeconds; if (diffInSeconds < 60) { return `${diffInSeconds} second${diffInSeconds === 1 ? "" : "s"} ago`; } else if (diffInSeconds < 3600) { const minutes = Math.floor(diffInSeconds / 60); return `${minutes} minute${minutes === 1 ? "" : "s"} ago`; } else if (diffInSeconds < 86400) { const hours = Math.floor(diffInSeconds / 3600); return `${hours} hour${hours === 1 ? "" : "s"} ago`; } else if (diffInSeconds < 2592000) { const days = Math.floor(diffInSeconds / 86400); return `${days} day${days === 1 ? "" : "s"} ago`; } else if (diffInSeconds < 31536000) { const months = Math.floor(diffInSeconds / 2592000); return `${months} month${months === 1 ? "" : "s"} ago`; } else { const years = Math.floor(diffInSeconds / 31536000); return `${years} year${years === 1 ? "" : "s"} ago`; } };
测试验证
使用你的测试代码验证:
const targetUnixTimestampInSeconds = 1689875101441 / 1000; // 毫秒转秒 console.log(fromNow(targetUnixTimestampInSeconds)); // 输出与moment一致的结果 console.log(moment(1689875101441).fromNow());
修正后,函数会正确计算UTC时间差,输出结果与moment.js的fromNow()保持一致。
内容的提问来源于stack exchange,提问作者Dennys Joseph
相关产品推荐
相关产品推荐

