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

时间:2009-06-24 06:44:45

标签: javascript date

我正在编写一个设备租赁应用程序,根据租赁期限(以天为单位)向客户收取租用设备的费用。所以,基本上,(每日费用*天数)=总费用。

对于客户端的即时反馈,我正在尝试使用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(),它似乎工作得很好(参见this post的例子)。我只是在Javascript中找不到等效的解决方案。

有人有什么想法吗?

15 个答案:

答案 0 :(得分:46)

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

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);
}

答案 1 :(得分:19)

我刚遇到这个问题并在找到这个问题后解决了,所以我回来发帖了。无论时间如何,这都将获得总天数。 DST不会弄乱它:

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日期。

答案 2 :(得分:10)

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

另一方面,由于我也在租赁设备软件行业,看起来你不计算小时数就会损失租金收入。根据你的例子,如果有人在7月6日早上6点拿起设备,并在7月7日晚上10点归还。他们有两整天的时间来使用这些设备,并且可能还会产生超额的电量......

答案 3 :(得分:10)

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

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

在上面的许多例子中,我们看到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)  );
}

答案 4 :(得分:7)

我还建议您查看令人难以置信的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.js diff:

的一些示例
> 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()转换为标准化时区。

答案 5 :(得分:6)

由于Julian日实际上是自某个日期以来的天数(在某些情况下也是天数的一小部分),因此它实际上与UNIX时间戳相同,呈现的方式不同。你可以得到自1970年以来的整天数量:

Date.prototype.getWholeDays = function () {
    return Math.floor(new Date() / 1000*60*60*24);
};

function dateDiff(startDate, endDate) {
    return endDate.getWholeDays() - startDate.getWholeDays();
}

答案 6 :(得分:3)

如果您只想要天数的差异,请务必使用UTC(GMT),否则如果夏令时开始或在间隔期间结束,减法将不会产生整数天的秒数。

答案 7 :(得分:2)

我曾经检查过dateiff函数的结果,该函数在18世纪使用Excel的.getTime()。结果返回正确。我有另一种计算不同日期的方法:

    function DaysOfYear(nYear) {
        if ((nYear % 4) == 0) {
            return 366;
        }
        else {
            return 365;
        }
    }


    function DiffDays(fDate, tDate) {
        var fYear = fDate.getFullYear();
        var tYear = tDate.getFullYear();
        var fMonth = fDate.getMonth();
        var tMonth = tDate.getMonth();
        var fDay = fDate.getDate();
        var tDay = tDate.getDate();
        var nDays = 0;

        if (tYear > fYear) {   // different year
            // remain days of from year
            nDays = DaysOfYear(fYear) - YTD_Days(fDate);
            // days of between fYear to tYear
            for (y = (fYear + 1); y < tYear; y++) {
                nDays = nDays + DaysOfYear(y);
            }
            // days from the beginning of tYear
            nDays = nDays + YTD_Days(tDate);
        }
        else {   // in the same year
            nDays = YTD_Days(tDate) - YTD_Days(fDate);
        };
        return nDays;
    }

    function YTD_Days(dDate) {
        var y = dDate.getFullYear();
        var m = dDate.getMonth();
        var nDays = 0

        for (i = 0; i < m; i++) {
            switch (i) {
                case 0:     // January
                    nDays = nDays + 31;
                    break;
                case 1:     // February
                    if ((y % 4) == 0) {
                        nDays = nDays + 29;
                    }
                    else {
                        nDays = nDays + 28;
                    };
                    break;
                case 2:     // March
                    nDays = nDays + 31;
                    break;
                case 3:     // April
                    nDays = nDays + 30;
                    break;
                case 4:     // May
                    nDays = nDays + 31;
                    break;
                case 5:     // June
                    nDays = nDays + 30;
                    break;
                case 6:     // July
                    nDays = nDays + 31;
                    break;
                case 7:     // August
                    nDays = nDays + 31;
                    break;
                case 8:     // September
                    nDays = nDays + 30;
                    break;
                case 9:     // October
                    nDays = nDays + 31;
                    break;
                case 10:     // November
                    nDays = nDays + 30;
                    break;
                case 11:     // December
                    nDays = nDays + 31;
                    break;
            }
        }
        nDays = nDays + dDate.getDate();
        return nDays;
    }

答案 8 :(得分:1)

您可以将开始日期调整为同一天的午夜,然后计算日期之间的24小时段数。然后,根据您是否想要将一天中的任何一部分计算为一整天,您可以采用该数字的上限或下限。

function dateDiff(startDate, endDate) {
    // set startDate to the beginning of the day
    startDate = new Date(
        startDate.getFullYear(),
        startDate.getMonth(),
        startDate.getDate());

    return Math.floor((endDate - startDate) / 1000*60*60*24);
}

答案 9 :(得分:1)

使用setHours()方法,假设天数永远不能为零:)

function dateDiff1(startDate, endDate) {
    endDate.setHours(0);
    startDate.setHours(0);
    //assuming days cannt be 0.

    var x = ((endDate.getTime() - startDate.getTime()) / 1000*60*60*24);
    if (x <1 && x>=0) {
        return 1;
    }
    return x;
}

答案 10 :(得分:1)

要获取整天的日期间隔而不是夏令时更改,则必须用圆形替换楼层(天)。否则它是一个非常有用的功能。

答案 11 :(得分:0)

以上使用UTC构造函数的示例。如果不这样做,你将受到夏令时/夏令时的破坏。

如果你采取其中一些差异,当你在一个方向穿越你的时区的DST线时可能会缩短一个小时(例如,春季前进,意味着2月要求4月)。当你下N + 23/24时,你最终会得到N。

另一个方向(十月份要求十二月)应该没问题,你将提前一小时结束,楼层()将正确处理。

答案 12 :(得分:0)

出于好奇:

如果你能确认结果总是是&lt; 31天,以下是一个解决方案:

var deltaDays = new Date(endDate - startDate).getDate()-1

为什么?

好好分解前一行:

var msecs = endDate - startDate; // difference in milliseconds
var dt = new Date(msecs); // will give us a date object pointing to a time 
                          // somewhere in Jan 1970 (given the precondition above)
var days = dt.getDate();  // Take the day part of it
var deltaDays = days - 1; // since the numbering starts from 1, we have to 
                          // substract 1 (Ex. if the diff in msecs is 0. The
                          // Date will point to 1st of Jan 1970)

但显然你应该使用它,如果你的结果可以是&gt; 31。

答案 13 :(得分:0)

需要date.js,http://code.google.com/p/datejs/

function CalculateDuration(startDate,endDate){

var sdt = Date.parse(startDate);
var edt = Date.parse(endDate);

var sdtYear = sdt.getYear();
var edtYear = edt.getYear();
var sdtMonth = sdt.getMonth();
var edtMonth = edt.getMonth();
var sdtDay = sdt.getDate();
var edtDay = edt.getDate();

var StartDateMonthDays = Date.getDaysInMonth(sdtYear, sdtMonth);
var EndDateMonthDays = Date.getDaysInMonth(edtYear, edtMonth);

if (edtMonth < sdtMonth) { //Means the ending month is earlier, which invalidates the operation

    alert("Ending month cannot be earlier than the starting month")

}

//Months are equal, if month is the next month of the start date month, 
//the operation fails, thus we need to calculate month difference first
else if (edtMonth > sdtMonth) {

    //Need to count how many days are left to finish the month
    var daysToMonthFinish = StartDateMonthDays - sdtDay;
    var calculatedDuration = daysToMonthFinish + edtDay;
    $("#hdn_duration").val(calculatedDuration);

}
//If months are the same, it is safe to just calculate the end day minus the start day
else {

    var calcDuration = edtDay - sdtDay;
    $("#hdn_duration").val(calcDuration);
}

答案 14 :(得分:0)

我知道这是一个部分解决方案,但您可以获得日期之间的日期(只要日期没有设定时间)。然后你可以在那里工作。

我的解决方案是基于您提出的问题((每日费用*天数)=总费用);不是实际的日期差异问题。这应该可以帮到你。

var Main = function() {
    var startDate = new Date('08/20/2014');
    var endDate = new Date('08/22/2014');
    var totalCharge = monthlyFee * daysBetween(startDate, endDate);
}

var daysBetween = function(startDate, endDate) {
    return Math.round(Math.abs((startDate.getTime() - endDate.getTime())/(24*60*60*1000)));
};