最稳方式是用new Date()构造日期对象再算毫秒差:传时间戳或标准化字符串(如"2023/06/01"),调用Math.abs(end-start)/(10006060*24)并Math.floor取整,全端兼容;避免直接解析"2023-06-01"等短横线格式。

uni-app里用new Date()算天数差最稳
直接用new Date()构造两个日期对象,再用毫秒差除以 1000 * 60 * 60 * 24 得整数天数,是 uni-app 全端兼容性最高、最不容易出错的方式。别碰字符串比对或手动拆年月日——iOS 微信小程序对"2023-06-01"这种格式解析不稳定,而new Date(2023, 5, 1)(注意月份从 0 开始)则全平台一致。
常见错误现象:new Date("2023-06-01") 在 H5 正常,在微信小程序可能返回 Invalid Date;getMonth() 忘记减 1 导致月份错位;没用Math.abs()导致负数天数。
- 输入必须是标准格式或数字时间戳:优先传毫秒时间戳(如
1718234567000),其次用new Date(year, monthIndex, date) - 字符串时间务必先标准化:把
"2023-06-01"换成"2023/06/01"再传给new Date() - 计算后一定要
Math.floor()或parseInt()取整,浮点误差会导致多出 0.9999 天
function getDaysDiff(startDate, endDate) {
const start = typeof startDate === 'number'
? new Date(startDate)
: new Date(startDate.replace(/-/g, '/'));
const end = typeof endDate === 'number'
? new Date(endDate)
: new Date(endDate.replace(/-/g, '/'));
return Math.floor(Math.abs(end - start) / (1000 * 60 * 60 * 24));
}
// 调用示例
getDaysDiff('2026-10-20', '2026-10-30') // → 10
用moment.js的diff()要注意包体积和时区
如果你项目已引入moment.js,diff()确实写起来最简洁,但得清楚它默认按本地时区算,且在 App 和小程序里会增大包体积约 200KB。它不解决底层兼容问题,只是语法糖。
使用场景:仅限已有 moment 依赖、且对包大小不敏感的管理后台类 H5 项目;电商小程序慎用。
-
diff()单位必须显式指定,如.diff(start, 'days'),漏掉'days'会返回毫秒值 - 传入字符串时,moment 内部仍会调用
new Date(),所以同样受"2023-06-01"解析失败影响 - 跨月/跨年计算时,
diff('months')返回的是“完整月份数”,不是日历月差,比如 1 月 31 日到 2 月 28 日返回 0
const start = this.$moment('2026/10/20');
const end = this.$moment('2026/10/30');
const days = end.diff(start, 'days'); // → 10
服务端返回时间戳时,别自己转字符串再算
后端如果给的是秒级时间戳(如 expire_time: 1718234567),前端千万别先format成"2023-06-01"再传给日期函数——这多一次无谓转换,还引入时区和格式化 bug 风险。直接乘 1000 当毫秒戳用最干净。
性能影响:每次 format + parse 是两次时间对象创建,低端安卓机上可感知卡顿;而expire_time * 1000 - Date.now()是纯数值运算,快一个数量级。
- 秒级戳 → 毫秒级:统一用
expire_time * 1000,别用parseInt(expire_time) * 1000(多余) - 别在 data 里存格式化后的字符串时间,只存原始戳,需要显示时再格式化
- 倒计时类逻辑中,天数差应实时算:
Math.max(0, Math.floor((endTime - Date.now()) / 86400000))
为什么uni-dateformat不适合算时间差
uni-dateformat是展示组件,不是计算工具。它的threshold参数只控制「何时触发简化显示」(如[60000, 3600000]表示 1 分钟内显示“刚刚”,1 小时内显示“X 分钟前”),它内部不暴露差值,也没提供diff()方法。
容易踩的坑:有人试图用来“看”是否超过一天,这是误用——它只决定文案,不返回数值,也无法用于逻辑判断(比如“超 3 天就标红”)。
- 真正需要数值差,请回到
new Date()或moment.diff() -
uni-dateformat只该用在这类纯展示场景{{ item.create_time | formatDate }} - 它不处理两个时间之间的关系,只处理单个时间点相对于“现在”的语义映射
实际开发中最容易被忽略的一点:时间差计算结果要配合业务语义做校验。比如“距活动开始还有 X 天”,X 为负数时不能直接显示“-2 天”,而应转为“已开始”或“进行中”——这个判断不在日期计算层,而在业务逻辑层,但很多人把它和getDaysDiff()混在一起写,导致复用性极差。











