Javascript 中的日期差异(忽略一天中的时间)

IT技术 javascript date
2021-02-16 08:09:24

我正在编写一个设备租赁应用程序,其中根据租赁的持续时间(以天为单位)向客户收取租赁设备的费用。因此,基本上,(每日费用 * 天数)= 总费用。

对于客户端的即时反馈,我正在尝试使用 Javascript 来找出两个日历日期的差异。我四处寻找,但没有找到我想要的东西。我见过的大多数解决方案都是以下形式:

function dateDiff1(startDate, endDate) {
    return ((endDate.getTime() - startDate.getTime()) / 1000*60*60*24);
}

我的问题是设备可以在这两个日期的任何时间检查和归还,无需额外费用。上面的代码正在计算两个日期之间的 24 小时周期数,当时我对日历天数很感兴趣。

例如,如果有人在 7 月 6 日早上 6 点检查设备并在 7 月 7 日晚上 10 点归还设备,则上面的代码将计算出超过 24 小时的时间段,并返回 2。所需的结果是 1,因为只有一个日历日期过去了(即第 6 天到第 7 天)。

我找到的最接近的解决方案是这个函数:

function dateDiff2(startDate, endDate) {
    return endDate.getDate() - startDate.getDate();
}

只要两个日期在同一个月内,这正是我想要的。但是,由于 getDate() 只返回月份中的第几天(即 1-31),当日期跨越多个月份时它不起作用(例如 7 月 31 日到 8 月 1 日是 1 天,但上面计算的是 1 - 31,或者-29)。

在后端,在 PHP 中,我使用 gregoriantojd(),它似乎工作得很好(请参阅此帖子的示例)。我只是在 Javascript 中找不到等效的解决方案。

有人有想法么?

6个回答

如果您想为您的学生相机租赁示例一整天...

function daysBetween(first, second) {

    // Copy date parts of the timestamps, discarding the time parts.
    var one = new Date(first.getFullYear(), first.getMonth(), first.getDate());
    var two = new Date(second.getFullYear(), second.getMonth(), second.getDate());

    // Do the math.
    var millisecondsPerDay = 1000 * 60 * 60 * 24;
    var millisBetween = two.getTime() - one.getTime();
    var days = millisBetween / millisecondsPerDay;

    // Round down.
    return Math.floor(days);
}
解决方案是使用 Math.round 而不是 ceil/floor。
2021-04-24 08:09:24
要考虑/允许负数,请换出Math.floor()for 条件语句:return second > first ? Math.floor(days) : Math.ceil(days);
2021-04-25 08:09:24
请记住在 Math.floor() 之前调用 Math.abs(),如果“first”可能发生在“second”之前。
2021-05-05 08:09:24
同意,Math.floor如果您位于Brasilia等时区,则使用会导致错误,DST 在午夜结束。有两种可能的解决方案:1)Math.round代替使用,或 2) 始终Date.UTC直接用于计算,就像在 sheriffpony 的解决方案中所做的那样
2021-05-11 08:09:24
对不起,但这不起作用。用这个值试试,会失败: one = new Date(2014, 2, 29); 二 = 新日期(2014, 2, 31); 将返回 1 天而不是 2 天!
2021-05-15 08:09:24

我刚遇到这个问题,找到这个问题后解决了,所以我回来贴这个。无论时间如何,这都将获得总天数。夏令时不会搞砸:

date1 = Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate());
date2 = Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate());
var ms = Math.abs(date1-date2);
return Math.floor(ms/1000/60/60/24); //floor should be unnecessary, but just in case

诀窍是转换为一个 UTC 日期,它甚至不知道原始日期的时间。

也使用了这种方法 - 需要确定两个日期之间的天数。这是最简单的一种,不考虑时间和地板/天花板。
2021-04-19 08:09:24

我要做的是将两个日期的时间设置为同一时间。例如,将 endDate 的时间设置为 12:00 am,将 startDate 的时间也设置为 12:00 am。然后得到它们之间的差异。

附带说明一下,由于我也从事租赁设备软件行业,因此如果不计算小时数,您似乎正在损失租赁收入。根据您的示例,如果有人在 7 月 6 日早上 6 点拿起设备并在 7 月 7 日晚上 10 点归还。他们有整整​​两天的时间来使用这些设备,而且还可能产生过多的电表费……

那是个很好的观点。不过,我们是一家学生经营的电视台,因此租金更多地是为了鼓励合理的租赁时间,而不是为了盈利。我们每天只收取约 5 美元的相机费用。
2021-05-09 08:09:24
为什么这个答案在没有解决问题的第二部分时被标记为正确,即。当日期在不同的月份时?
2021-05-14 08:09:24

给定的解决方案中存在错误!

这适用于忽略时间并且您想要整数结果(即整数天)的日期差异。

在上面的许多示例中,我们看到了 Math.floor 其他实例,我也在其他地方看到了 Math.ceil。这样做是为了将结果四舍五入到整数天。问题是夏令时会在秋季使用 Math.ceil 给出错误的结果——你的结果有一天会太大,或者在春季,如果你使用 Math.floor,你会少一天。只需使用 Math.round,因为无论哪种方式 1 小时都不会扭曲结果。

function dateDiff(dateEarlier, dateLater) {
    var one_day=1000*60*60*24
    return (  Math.round((dateLater.getTime()-dateEarlier.getTime())/one_day)  );
}
我认为 OP 希望 1 月 1 日 23:59 和 1 月 2 日 00:01 相差 1 天。
2021-05-15 08:09:24

我还建议看看令人难以置信的moment.js库。它有一个通用的diff功能,你可以用它来解决上面的例子,如下所示:

function is_same_date(startDate, endDate) {
   var startMoment = moment(startDate).clone().startOf('day'),
       endMoment = moment(endDate).clone().startOf('day');
   return startMoment.diff(endMoment, 'days') == 0;
}

以下是一些使用moment.jsdiff 的示例

> d1 = new Date(2012,04,04,0,0)
Fri May 04 2012 00:00:00 GMT-0400 (EDT)

> d2 = new Date(2012,04,03,23,0)
Thu May 03 2012 23:00:00 GMT-0400 (EDT)

> d3 = new Date(2012,04,05,23,0)
Sat May 05 2012 23:00:00 GMT-0400 (EDT)

> moment(d2).diff(d1, 'days')
0

> moment(d1).diff(d2, 'days')
0

> moment(d1).diff(d3, 'days') // uh oh. this is why we use `startOf`
-2

> moment(d2).diff(d3, 'days')
-2

> moment(d3).startOf('day') // this modified d3, sets the time to 00:00:00.0000
> d3
Sat May 05 2012 00:00:00 GMT-0400 (EDT)

如果时区是一个问题,您还可以使用moment.utc()转换为规范化时区。

@SalmanHasratKhan 好问题——如果您不使用,.clone那么矩库将修改基础日期对象。
2021-04-20 08:09:24
为什么在调用 startOf() 之前使用 clone()?
2021-04-26 08:09:24