【问题标题】:Why doesn't moment.js year diff year not match exactly 1?为什么 moment.js year diff year 不完全匹配 1?
【发布时间】:2015-08-05 20:00:54
【问题描述】:

我已经执行了这些简单的 JS 代码行

moment.duration(moment(new Date(2013,1,1)).diff(moment(new Date(2012,1,1)))).asYears()
moment.duration(moment(new Date(2012,1,1)).diff(moment(new Date(2011,1,1)))).asYears()
moment.duration(moment(new Date(2011,1,1)).diff(moment(new Date(2010,1,1)))).asYears()
moment.duration(moment(new Date(2010,1,1)).diff(moment(new Date(2009,1,1)))).asYears()

输出

1.0020739645577939
0.9993360575508053
0.9993360575508053
0.9993360575508053

肯定有什么问题吧?

或者这种异常可能与闰年有关? 2012年是闰年

所以我尝试了下一个闰年 2016

moment.duration(moment(new Date(2016,1,1)).diff(moment(new Date(2015,1,1)))).asYears()

它的输出与之前的非闰年相同,所以可能与它无关

0.9993360575508053

有人知道发生了什么吗?

【问题讨论】:

标签: javascript datetime momentjs


【解决方案1】:

首先,请注意new Date(year,1,1) 指的是2 月 1 日,而不是 1 月。 Javascript,遵循 UNIX time_t 约定,从 0 开始编号月份,其想法是您将使用月份编号来索引月份名称数组,而不是直接使用它。所以要构造一个引用 1 月 1 日的 Date 对象,你应该调用new Date(year,0,1)

其次,取整数天数的差值并转换为年数永远不会得到整数。你应该首先让 Moment 给出年份的差异:

> moment(new Date(2013,0,1)).diff(moment(new Date(2012,0,1)),'year');
1

如果您希望结果包含一年的小数部分而不是截断为整数,请向diff 添加一个真实的第三个参数。这里我们从 7 月算到 1 月:

> moment(new Date(2013,0,1)).diff(moment(new Date(2012,6,1)),'year',true)
0.5

您的方法不起作用,因为日历年不是固定的秒数;要么是 365 天,即 31,536,000 秒,要么是 366 天,即 31,622,400 秒。由于闰年通常每四年发生一次,因此平均日历年为 365.25 天,即 31,557,600 秒;事实上,光年的定义是光在该精确秒数内传播的距离。

但在现代公历中,闰世纪规则意味着一年的平均长度(您必须花费 400 多年才能获得一个完整的周期)实际上要短一些:365.2425 天或 31,556,952 秒。这是 Moment 使用的值,但它仅作为平均值起作用;任何不是 400 年精确倍数的周年纪念日都不会给出整数结果。相反,正如您所发现的,普通年将计为 31,536,000 / 31,556,952 = 0.99933605755085028689843... 一年,而闰年将计为 31,622,400 / 31,556,952 = 1.00207396455779...6 年。>

在您的上一个示例中,您得到了共同年份值,因为您要求的是从 2015 年到 2016 年的年份长度 - 这是 2015 年的长度。如果从 2016 年到 2017 年计算,您会得到预期的飞跃年值:

> moment.duration(moment(new Date(2017,0,1)).diff(moment(new Date(2016,0,1)))).asYears()
1.0020739645577939

更具体地说,只要间隔包括 2 月 29 日,您就会得到闰年长度。因此,如果您要测量连续年份同一日期之间的增量,如果您从闰年前一年的 3 月 1 日到闰年本身的 2 月 28 日之间的任何日期开始,您将得到 366 天。如果从 2 月 29 日开始计算,那当然没有次年的 2 月 29 日;如果您数到 2 月 28 日,您将获得 365 天,如果您数到 3 月 1 日,您将获得 366 天。从闰年的 3 月 1 日开始,到同一日期重复的时间回到 365 天:

> moment.duration(moment(new Date(2016,1,28)).diff(moment(new Date(2015,1,28)))).asYears()
0.9993360575508053
> moment.duration(moment(new Date(2016,2,1)).diff(moment(new Date(2015,2,1)))).asYears()
1.0020739645577939
> moment.duration(moment(new Date(2017,1,28)).diff(moment(new Date(2016,1,28)))).asYears()
1.0020739645577939
> moment.duration(moment(new Date(2017,2,1)).diff(moment(new Date(2016,2,1)))).asYears()
0.9993360575508053

【讨论】:

  • 很好的答案。这很好用。但是我期待像 moment(new Date(2013,1,1)).diff(moment(new Date(2012,6,1)),'year');返回 0.5,但它返回 0
  • 想通了。我只需要在 'year' 之后添加一个 true 作为额外参数
  • 谢谢你,@Daniel;我已将其纳入答案。
【解决方案2】:

尝试使用:

moment(new Date(2013,1,1)).diff(moment(new Date(2012,1,1)),'year');

【讨论】:

    猜你喜欢
    • 2014-12-03
    • 2019-05-02
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 2012-03-17
    • 2012-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多