Moment.js中duration计算时间间隔结果异常问题排查
Moment.js计算时间间隔结果不符合预期?
问题场景
我想用Moment.js计算两个日期的时间间隔,代码如下:
var start = moment("2016-05-04 13:00:00"); var end = moment("2018-05-04 13:00:00"); var diff = moment(end).diff(start); var duration = moment.duration(diff); var years = duration.years(); var months = duration.months(); var days = duration.days(); var hours = duration.hours(); var minutes = duration.minutes(); console.log(years + " years " + months + " months " + days + " days " + hours + " hours " + minutes + " minutes ");
引入的Moment.js脚本:
<script src="https://momentjs.com/downloads/moment.js"></script>
预期输出是2 years 0 months 0 days 0 hours 0 minutes,但实际得到的是1 years 11 months 29 days 0 hours 0 minutes,这是为什么?
问题原因
核心问题出在**moment.duration()的工作逻辑**上:
- 你用
diff()不带参数时,返回的是两个日期之间的总毫秒数。 moment.duration()是把这个毫秒数转换成近似的持续时长——它是按**平均年份(365天)、平均月份(约30.44天)**来拆分数值的,完全不考虑实际日历中的月份天数、闰年等因素。
具体到你的例子:2016-05-04到2018-05-04实际是731天(2016年是闰年,从5月4日到次年5月4日是366天,加上2017-2018的365天)。把731天转换成毫秒后,除以平均一年的365天,得到的是1年多,剩下的天数再除以平均月份的天数,得到11个月多,最后剩下29天,就出现了你看到的不符合预期的结果。
解决方案
如果要得到日历上的精确间隔(即实际过了多少年、多少个月,而非按平均时长估算),需要基于日历一步步计算差值:
var start = moment("2016-05-04 13:00:00"); var end = moment("2018-05-04 13:00:00"); // 先计算年份差,然后把年份加到起始日期上 var years = end.diff(start, 'years'); start.add(years, 'years'); // 基于更新后的起始日期计算月份差,再更新起始日期 var months = end.diff(start, 'months'); start.add(months, 'months'); // 依次计算天、小时、分钟的差值 var days = end.diff(start, 'days'); start.add(days, 'days'); var hours = end.diff(start, 'hours'); start.add(hours, 'hours'); var minutes = end.diff(start, 'minutes'); console.log(`${years} years ${months} months ${days} days ${hours} hours ${minutes} minutes`);
这段代码会输出你预期的2 years 0 months 0 days 0 hours 0 minutes,因为它是基于实际日历的日期变化来计算每个单位的差值,而非用总毫秒数做平均估算。
内容的提问来源于stack exchange,提问作者lebendig
相关产品推荐
相关产品推荐

