日期计算出现奇怪的错误

3
我需要计算两个日期之间相差的年数。我的代码运行正常,但对于某些特定的日期会出现问题。
下面的代码应该会给出dateEnddateEnd1相同的年份差,但实际上结果是不相等的。如果我将年份从2003改为2004,则它们将相等。如果我保留年份不变,但将三月改成二月,它们也将相等。
我猜这可能与闰年有关,但我不知道原因。尤其是在那段时间内有4个闰年,但年份计算错误发生在相隔一天的日期上。
我期望在这两种情况下得到的年份差都是12,但是对于变量dateEnd,我得到的却是13。
var dateStart = '2003,03,11';
var dateEnd = '2016,03,10';
var dateEnd1 = '2016,03,09';

var difference = (new Date(dateEnd)).getTime() - (new Date(dateStart)).getTime();
difference = (new Date(difference)).getFullYear() - 1970;
alert('Between ' + dateStart + ' and ' + dateEnd + ' elapsed ' + difference + ' years.');
difference = (new Date(dateEnd1)).getTime() - (new Date(dateStart)).getTime();
difference = (new Date(difference)).getFullYear() - 1970;
alert('Between ' + dateStart + ' and ' + dateEnd1 + ' elapsed ' + difference + ' years.');

这里是在 jsfiddle 上的代码。评论区一位人成功地在他的 jsfiddle 上重现了问题!
这里是我获得的变量值:
dateStart time: 1047337200000
dateEnd time: 1457564400000
dateEnd1 time: 1457478000000
Time difference for the first case: 410227200000
Between 2003,03,11 and 2016,03,10 elapsed 13 years.
Time difference for the second case: 410140800000
Between 2003,03,11 and 2016,03,09 elapsed 12 years.

2
它相等吗?我两次都得到了12。 - bobek
3
这可能是地区问题吗?根据我们的配置文件,Bobek和我都在美国(我的结果也是12),而你在比利时。从我在 MDN 上看到的内容来看,“03/11/2003”似乎不是构建日期的受支持格式,尽管MSDN表示IE应该支持它。 - DocMax
1
如果你只需要年份,那么仅减去年份而不必担心秒、分钟、小时和天数是否更好呢?(new Date(dateEnd)).getFullYear() - (new Date(dateStart)).getFullYear()) - dsh
1
你可以考虑简单地比较年、月和日(如果必要的话)。或者,你可以将毫秒差转换为天数,并除以365.25。这不是精确的,但可能比当前的闰年和夏令时问题更好。 - Doug Domeny
1
@MarkoD,发现得好。http://jsfiddle.net/ZFJgt/1/ 显示为12/13。这将把语言环境重新引入到框架中。 - Beetroot-Beetroot
显示剩余22条评论
2个回答

2

这与地区无关。当我将日期更改为2016年的任何其他月份时(除了1月和2月),我也会得到12/13的结果。原因是2016年是闰年,而2003年不是。

这证明了使用日期来计算日期差异是不可靠的。为了计算年份差异,您需要使用两个日期的年份部分。还需要比较月份部分,如果结束月份在开始月份之前,则减去一年,如果开始月份和结束月份相同,则还需要比较日期的天数。如果需要,还可以包括小时、分钟、秒和毫秒。


我不这么认为。如果我将其与2005年(这也不是闰年)或2004年(这是闰年)进行比较,它就不会发生。它也会在2002年发生,但不会在2001年发生! - Marko D
当我将2003更改为2007和/或2016更改为2012时,我会得到类似的错误结果。当您使用2005而不是2003时,总天数减少了365 + 366天,这足以防止舍入问题,从而不会产生错误。 - Arjan

2

无法/可以重现的差异不在于语言环境,而是时区。对我来说(在加利福尼亚州),以上值为:

alert(new Date(410140800000)); // "Thu Dec 30 1982 16:00:00 GMT-0800 (Pacific Standard Time)"
alert(new Date(410227200000)); // "Fri Dec 31 1982 16:00:00 GMT-0800 (Pacific Standard Time)"

如果我在格林尼治标准时间或东部时区,第二个日期将是"Sat Jan 1 1983...",这会导致年数的不同。闰年可能与此有关,因为闰年的数量影响差异中的天数。
我认为如果你使用2005/2018,你会看到相同的东西,但正如Arjan指出的那样,它并不那么简单,确实涉及闰年。

感谢您的回答。2005/2018可以产生正确的结果!但是2007/2020则不行。 - Marko D
最终看起来问题是闰日和格林威治标准时间以东的时区的组合。 - DocMax
1975年1月1日星期三01:00:00 GMT+0100(CET) 2007年8月11日至2012年8月10日间经过了5年。 1974年12月31日星期二01:00:00 GMT+0100(CET) 2007年8月11日至2012年8月9日间经过了4年。 - Arjan
是的。对我来说,第一个日期应该是“1974年12月31日星期二 16:00:00 GMT-0800”,持续了4年,这就是为什么我无法重新创建它。 - DocMax
1
这就是为什么这种日期计算方法不准确的原因。这些问题很难检测,因为它们只出现在非常特定的情况下。 - Arjan
我至少很幸运,在开始测试随机日期时就找到了这个错误...看来我得手动比较日期片段。谢谢你们的帮助! - Marko D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接