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

我正在写一个设备租赁申请,根据租赁期限(以天计),向客户收取租用设备的费用。 所以基本上(每日费用*天数)=总费用。

对于客户端的即时反馈,我试图用Javascript来计算两个日历date的差异。 我搜查了一下,但没有find我正在寻找的东西。 我见过的大多数解决scheme的forms是:

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

我的问题是设备可以在这两个date的任何时候检查出来,并且不收取额外费用。 上面的代码是计算两个date之间24小时的时间段,当我真正感兴趣的日历天数。

例如,如果有人在7月6日上午6点检查了设备,并在7月7日晚上10点将其返还,上面的代码会计算出超过一个24小时的时间过去了,并且返回2.期望的结果是1,因为只有一个日历date已过(即第六至第七)。

我find的最接近的解决scheme是这个function:

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

只要这两个date在同一个月内,就完全符合我的要求。 但是,由于getDate()只返回一个月份的date(即1-31),所以当date跨越多个月份时(例如7月31日到8月1日是1天,但是上面的计算1-31或-29)。

在后端,在PHP中,我使用gregoriantojd(),这似乎工作得很好(看到这个post的例子)。 我只是找不到在Javascript中的等效解决scheme。

任何人有任何想法?

如果你想整天为你的学生相机租赁的例子…

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

我刚刚遇到这个问题,find这个问题后就解决了,于是我回来发post。 不pipe时间如何,这将获得总天数。 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 

技巧是转换为UTCdate,甚至不知道原始date的时间。

我会做的是设置两个date的时间在同一时间。 例如,将endDate的时间设置为12:00 am,startDate的时间设置为12:00 am。 然后得到他们之间的差异。

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

在给定的解决scheme中有一个错误!

这适用于不考虑时间的date差异,并且您需要整数结果,即整个天数。

在上面的许多例子中,我们看到Math.floor其他的例子,我也看到了Math.ceil的其他地方。 这些都是将结果四舍五入到整数天。 问题是使用Math.ceil会导致夏令时的错误结果 – 如果你使用Math.floor,你的结果将会有一天太大,或者在spring,你将会有一天太less。 只要使用Math.round,因为1小时的任何一种方式都不会歪曲结果。

 function dateDiff(dateEarlier, dateLater) { var one_day=1000*60*60*24 return ( Math.round((dateLater.getTime()-dateEarlier.getTime())/one_day) ); } 

我还build议看一下令人难以置信的moment.js库。 它有一个多function的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()将其转换为规范化的时区。

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

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

如果您只需要天数差异,请务必使用UTC(格林尼治标准时间),否则如果夏令时开始或在间隔期间结束,相减将不会产生以秒为单位的整数天数。

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

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

您可以将开始date调整为同一天的午夜,然后计算date之间的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); } 

使用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; } 

为了获得整天的date间隔夏时制改变的地板(天)必须由一轮取代。 否则,这是一个非常有用的function。

+上面使用UTC构造函数的示例。 如果没有这样做,你会被夏时制/夏令营所破坏。

如果你把它们中的一些差异考虑进来,那么当你在一个方向上穿越DST时间线时(例如在2月份要求4月份的时候,它可能会在一个方向上跳过DST线一个小时)。 当你出发N + 23/24时,你会以N结尾。

另一个方向(10月份要求12月份)应该没问题,你最终会提前一个小时才能正确处理地板。

只是出于好奇:

如果你可以肯定结果总是 <31天,那么下面是一个解决scheme:

 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) 

但是,如果你的结果可以> 31,显然你不应该使用它。

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

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

我知道这是一个部分的解决scheme,但你可能能够得到date之间的日子(只要date没有时间设置)。 那么你可以从那里工作。

我把这个解决scheme与你提出的问题((每日费用*天数)=总费用); 不是实际的date差异问题。 这应该帮助你。

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