在JavaScript中获取两个日期之间的差异?

840

我如何获取两个日期之间的完整天数差异(不要有任何一天的零头)?

var date1 = new Date('7/11/2010');
var date2 = new Date('12/12/2010');
var diffDays = date2.getDate() - date1.getDate(); 
alert(diffDays)
我尝试了上面的方法,但它没有起作用。

46
请注意:不要使用这种字符串作为输入创建日期对象;它是非标准的,并且由浏览器解析方式不确定。请使用可以被 Date.parse 解析的字符串,或者更好的方式是将三个数字值作为参数传递给 new Date,例如 new Date(2010, 11, 7); - Marcel Korpel
4
侧记:永远不要相信客户端的系统时间!它经常是错误的,可能会破坏您的应用程序。 - Sliq
此外,可以尝试在 https://dev59.com/M3I-5IYBdhLWcg3wNle1#53092438 上测试一个小函数。 - Edward
6
@Edward,你真的把那称作一个小函数吗? :) - Ihor
1
这是无法解决的问题。1)2010年7月11日可能是7月11日,也可能是11月7日。2)时区是什么?这可能跨越日期变更线。3)没有时间,精度为+/- 1天。4)结果可能是负数,实际上应该是正数(或反之亦然),因为没有时间/时区。 - Andrew
5个回答

1265

这里有一种方法:

const date1 = new Date('7/13/2010');
const date2 = new Date('12/15/2010');
const diffTime = Math.abs(date2 - date1);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); 
console.log(diffTime + " milliseconds");
console.log(diffDays + " days");

注意需要用引号括起日期。代码的其余部分获取以毫秒为单位的时间差,然后进行除法运算以获取天数。Date 类型的日期格式应为 mm/dd/yyyy。


12
正如Volkan在下面回答的那样,1000 * 3600 * 24是一天的毫秒数。至于始终返回正数的原因,那是一个特性 :) 通常当谈论两个日期之间的天数时,该数字为正数。如果方向很重要,只需删除Math.abs()即可。 - TNi
2
同样地,由于getDate()返回的是不考虑月份的日期,因此您将获得1天。因此,您将得到12-11 = 1。 - TNi
5
无需调用.getTime()方法,日期已经返回时间。 - volkan er
12
为了正确处理夏令时,应该使用Math.round替换Math.ceil。但我认为Shyam的答案是可行的方式。 - Zemljoradnik
10
在计算时间跨度时,不适用于一天为23小时或25小时的情况。在制定这样的计算方法之前,最好先查阅有关协调世界时(UTC)和“民用”时间标准的详细处理方式。一天并不总是等于86,400秒,即使在UTC中也不是如此。然而,ECMA标准规定,它将不会有58、59、61或62秒的分钟,这种情况每年最多发生两次在UTC中。您不能假设其他语言和操作系统中的纪元偏移量(1970年1月1日00:00:00)将是相同的,因为其中一些具有58、59、61和62秒的分钟。 - Jim
显示剩余20条评论

1007

更正确的解决方案

... 由于日期本身自带时区信息,可能跨越有不同日光节约调整的地区

以前对这个问题的回答没有考虑到两个日期跨越夏令时(DST)变化的情况。发生DST变化的日期在毫秒级别上的持续时间 != 1000 * 60 * 60 * 24,所以常规计算方法会失败。

您可以通过先将两个日期转换为UTC标准时间,然后计算这两个UTC日期之间的差异来解决此问题。

现在,解决方案可以写成:

// a and b are javascript Date objects
function dateDiffInDays(a, b) {
  const _MS_PER_DAY = 1000 * 60 * 60 * 24;
  // Discard the time and time-zone information.
  const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
  const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());

  return Math.floor((utc2 - utc1) / _MS_PER_DAY);
}

// test it
const a = new Date("2017-01-01"),
    b = new Date("2017-07-25"),
    difference = dateDiffInDays(a, b);
    
console.log(difference + ' days')

这是因为UTC时间从不遵守夏令时。参见Does UTC observe daylight saving time?

p.s. 经过讨论评论后,一旦您了解跨越夏令时边界的JavaScript日期问题,可能有不止一种解决方法。我提供的是一个简单(并经过测试)的解决方案。如果有一种简单的基于算术/数学的解决方案而不必实例化两个新的Date对象,那将可能更快。


68
这是唯一正确的答案,我不理解为什么其他答案被接受。 - obenjiro
29
可能是因为 @chobo2 还没有回来查看这个问题。 - Shyam Habarakada
6
虽然这是最合乎逻辑的答案,但是它不会失败匹配更简单的 Math.round((b - a)/ _MS_PER_DAY, 0),因此很难支持“唯一正确的答案”这个说法。 - Scott Sauyet
1
去掉烦人的“alert”,加1 - IcanDivideBy0
14
使用协调世界时(UTC)代替本地时区可以纠正民用时间系统中由23小时和25小时天引起的问题。UTC每年还有58、59、61和62秒的情况,所以UTC一天不总是有86400秒。但是,ECMA标准规定JavaScript不包含这些调整,因此在纯粹使用JavaScript工作时可以忽略它们。然而,其他系统不会忽略它们,你不能假设自1970年1月1日 00:00:00时刻(时代起始日)开始的偏移量在编程语言和操作系统之间始终相同。 - Jim
显示剩余34条评论

59
var date1 = new Date("7/11/2010");
var date2 = new Date("8/11/2010");
var diffDays = parseInt((date2 - date1) / (1000 * 60 * 60 * 24), 10); 

alert(diffDays )

1
date2 - date1 => 毫秒输出 (1000 * 60 * 60 * 24) => 毫秒转天 - volkan er
11
parseInt完全没有必要吗? - Christian
3
基督徒:他想要一个整数。parseInt可能是最糟糕的方法。Math.round是“正常”的方法;它会四舍五入而不是截断。如果需要截断,则使用“或”运算符与0相结合即可:(date2 - date1) / (1000 * 60 * 60 * 24) | 0 - Dagg Nabbit
9
请注意,这个解决方案并不完全准确,因为在某些情况下,例如2015年4月6日减去2015年4月4日会出现错误的1天,这与parseInt()方法有关。 - ontananza
1
在使用夏令时的地区,一年中会有一天只有23个小时。 - Garr Godfrey
显示剩余4条评论

14

我尝试了很多方法,发现使用datepicker是最好的选择,但日期格式会导致JavaScript出现问题....

因此,这里是我的答案,可以直接运行。

<input type="text" id="startdate">
<input type="text" id="enddate">
<input type="text" id="days">

<script src="https://code.jquery.com/jquery-1.8.3.js"></script>
<script src="https://code.jquery.com/ui/1.10.0/jquery-ui.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" />
<script>
$(document).ready(function() {

$( "#startdate,#enddate" ).datepicker({
changeMonth: true,
changeYear: true,
firstDay: 1,
dateFormat: 'dd/mm/yy',
})

$( "#startdate" ).datepicker({ dateFormat: 'dd-mm-yy' });
$( "#enddate" ).datepicker({ dateFormat: 'dd-mm-yy' });

$('#enddate').change(function() {
var start = $('#startdate').datepicker('getDate');
var end   = $('#enddate').datepicker('getDate');

if (start<end) {
var days   = (end - start)/1000/60/60/24;
$('#days').val(days);
}
else {
alert ("You cant come back before you have been!");
$('#startdate').val("");
$('#enddate').val("");
$('#days').val("");
}
}); //end change function
}); //end ready
</script>

这里可以看到一个小小的演示DEMO


这是一个类似于我遇到的问题,但这个解决方案的问题是如果用户先点击日期选择器中的date2,那么它就会失败。 - user6743474

7
这是从一个日期中减去另一个日期的代码。此示例将日期转换为对象,因为 getTime() 函数只能在 Date 对象上使用才能正常工作。
    var dat1 = document.getElementById('inputDate').value;
                var date1 = new Date(dat1)//converts string to date object
                alert(date1);
                var dat2 = document.getElementById('inputFinishDate').value;
                var date2 = new Date(dat2)
                alert(date2);

                var oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
                var diffDays = Math.abs((date1.getTime() - date2.getTime()) / (oneDay));
                alert(diffDays);

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