我如何在JavaScript中计算出两个Date()对象的差异,而只返回差异中的月份数?
任何帮助都是最好的:)
我如何在JavaScript中计算出两个Date()对象的差异,而只返回差异中的月份数?
任何帮助都是最好的:)
当前回答
下面是一个函数,它精确地提供了两个日期之间的月数。 默认行为只计算整个月份,例如3个月和1天将导致3个月的差异。您可以通过将roundUpFractionalMonths参数设置为true来防止这种情况,因此3个月和1天的差异将返回为4个月。
上面公认的答案(T.J.克劳德的答案)是不准确的,它有时会返回错误的值。
例如,monthDiff(new Date('Jul 01, 2015'), new Date('Aug 05, 2015'))返回0,这显然是错误的。正确的差值是1个月或2个月。
这是我写的函数:
function getMonthsBetween(date1,date2,roundUpFractionalMonths)
{
//Months will be calculated between start and end dates.
//Make sure start date is less than end date.
//But remember if the difference should be negative.
var startDate=date1;
var endDate=date2;
var inverse=false;
if(date1>date2)
{
startDate=date2;
endDate=date1;
inverse=true;
}
//Calculate the differences between the start and end dates
var yearsDifference=endDate.getFullYear()-startDate.getFullYear();
var monthsDifference=endDate.getMonth()-startDate.getMonth();
var daysDifference=endDate.getDate()-startDate.getDate();
var monthCorrection=0;
//If roundUpFractionalMonths is true, check if an extra month needs to be added from rounding up.
//The difference is done by ceiling (round up), e.g. 3 months and 1 day will be 4 months.
if(roundUpFractionalMonths===true && daysDifference>0)
{
monthCorrection=1;
}
//If the day difference between the 2 months is negative, the last month is not a whole month.
else if(roundUpFractionalMonths!==true && daysDifference<0)
{
monthCorrection=-1;
}
return (inverse?-1:1)*(yearsDifference*12+monthsDifference+monthCorrection);
};
其他回答
它还计算天数并以月为单位进行转换。
function monthDiff(d1, d2) {
var months;
months = (d2.getFullYear() - d1.getFullYear()) * 12; //calculates months between two years
months -= d1.getMonth() + 1;
months += d2.getMonth(); //calculates number of complete months between two months
day1 = 30-d1.getDate();
day2 = day1 + d2.getDate();
months += parseInt(day2/30); //calculates no of complete months lie between two dates
return months <= 0 ? 0 : months;
}
monthDiff(
new Date(2017, 8, 8), // Aug 8th, 2017 (d1)
new Date(2017, 12, 12) // Dec 12th, 2017 (d2)
);
//return value will be 4 months
下面是另一种更少循环的方法:
calculateTotalMonthsDifference = function(firstDate, secondDate) {
var fm = firstDate.getMonth();
var fy = firstDate.getFullYear();
var sm = secondDate.getMonth();
var sy = secondDate.getFullYear();
var months = Math.abs(((fy - sy) * 12) + fm - sm);
var firstBefore = firstDate > secondDate;
firstDate.setFullYear(sy);
firstDate.setMonth(sm);
firstBefore ? firstDate < secondDate ? months-- : "" : secondDate < firstDate ? months-- : "";
return months;
}
有两种方法,数学的和快速的,但受制于日历的变幻莫测,或者迭代的和缓慢的,但处理所有奇怪的(或者至少委托处理它们到一个经过良好测试的库)。
If you iterate through the calendar, incrementing the start date by one month & seeing if we pass the end date. This delegates anomaly-handling to the built-in Date() classes, but could be slow IF you're doing this for a large number of dates. James' answer takes this approach. As much as I dislike the idea, I think this is the "safest" approach, and if you're only doing one calculation, the performance difference really is negligible. We tend to try to over-optimize tasks which will only be performed once.
现在,如果您在数据集中计算这个函数,您可能不希望在每一行上运行该函数(或者上帝禁止,每条记录多次)。在这种情况下,您几乎可以使用这里的任何其他答案,除了接受的答案,这是错误的(new Date()和new Date()之间的差异是-1)?
下面是我尝试的一种数学而快速的方法,它解释了不同的月份长度和闰年。你真的应该只使用这样的函数,如果你将应用它到一个数据集(做这个计算一遍又一遍)。如果只需要执行一次,可以使用上面James的迭代方法,因为您正在将所有(许多)异常的处理委托给Date()对象。
function diffInMonths(from, to){
var months = to.getMonth() - from.getMonth() + (12 * (to.getFullYear() - from.getFullYear()));
if(to.getDate() < from.getDate()){
var newFrom = new Date(to.getFullYear(),to.getMonth(),from.getDate());
if (to < newFrom && to.getMonth() == newFrom.getMonth() && to.getYear() %4 != 0){
months--;
}
}
return months;
}
当日期和时间无关紧要的月份数
在这种情况下,我不关心完整的月份,部分月份,一个月有多长等等。我只需要知道月数。一个相关的现实案例是每个月都有一份报告,我需要知道应该有多少份报告。
例子:
1月= 1个月 一月到二月= 2个月 11月至1月= 3个月
这是一个详细的代码示例,以显示数字的走向。
让我们取2个时间戳,结果应该是4个月
2019年11月13日的时间戳:1573621200000 2020年2月20日的时间戳:1582261140000
可能与您的时区/时间略有不同。日、分和秒并不重要,可以包含在时间戳中,但在实际计算中我们将忽略它。
步骤1:将时间戳转换为JavaScript日期
let dateRangeStartConverted = new Date(1573621200000);
let dateRangeEndConverted = new Date(1582261140000);
步骤2:获取月份/年的整数值
let startingMonth = dateRangeStartConverted.getMonth();
let startingYear = dateRangeStartConverted.getFullYear();
let endingMonth = dateRangeEndConverted.getMonth();
let endingYear = dateRangeEndConverted.getFullYear();
这给了我们
开始月份:11 开始年份:2019年 结束月份:2 结束年份:2020年
步骤3:在月末加上(12 * (endYear - startYear)) + 1。
这使我们的开始月停留在11 这样月末就等于15 2 + (12 * (2020 - 2019))+ 1 = 15
第四步:减去月份
15 - 11 = 4;我们得到了4个月的结果。
29个月
2019年11月至2022年3月为29个月。如果你把这些输入到excel电子表格中,你会看到29行。
开始的月份是11 最后一个月是403 + (12 * (2022-2019))+ 1
40 minus 11 is 29
function monthDiff(d1, d2) {
var months, d1day, d2day, d1new, d2new, diffdate,d2month,d2year,d1maxday,d2maxday;
months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth() + 1;
months += d2.getMonth();
months = (months <= 0 ? 0 : months);
d1day = d1.getDate();
d2day = d2.getDate();
if(d1day > d2day)
{
d2month = d2.getMonth();
d2year = d2.getFullYear();
d1new = new Date(d2year, d2month-1, d1day,0,0,0,0);
var timeDiff = Math.abs(d2.getTime() - d1new.getTime());
diffdate = Math.abs(Math.ceil(timeDiff / (1000 * 3600 * 24)));
d1new = new Date(d2year, d2month, 1,0,0,0,0);
d1new.setDate(d1new.getDate()-1);
d1maxday = d1new.getDate();
months += diffdate / d1maxday;
}
else
{
if(!(d1.getMonth() == d2.getMonth() && d1.getFullYear() == d2.getFullYear()))
{
months += 1;
}
diffdate = d2day - d1day + 1;
d2month = d2.getMonth();
d2year = d2.getFullYear();
d2new = new Date(d2year, d2month + 1, 1, 0, 0, 0, 0);
d2new.setDate(d2new.getDate()-1);
d2maxday = d2new.getDate();
months += diffdate / d2maxday;
}
return months;
}