JavaScript 中两个日期之间的月差

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2536379/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 00:47:39  来源:igfitidea点击:

Difference in Months between two dates in JavaScript

javascriptdatedatediff

提问by williamtroup

How would I work out the difference for two Date() objects in JavaScript, while only return the number of months in the difference?

我如何计算 JavaScript 中两个 Date() 对象的差异,同时只返回差异的月数?

Any help would be great :)

任何帮助都会很棒:)

回答by T.J. Crowder

The definition of "the number of months in the difference" is subject to a lot of interpretation. :-)

“差异月数”的定义有很多解释。:-)

You can get the year, month, and day of month from a JavaScript date object. Depending on what information you're looking for, you can use those to figure out how many months are between two points in time.

您可以从 JavaScript 日期对象中获取年、月和日。根据您要查找的信息,您可以使用这些信息来计算两个时间点之间有多少个月。

For instance, off-the-cuff:

例如,现成的:

function monthDiff(d1, d2) {
    var months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months -= d1.getMonth();
    months += d2.getMonth();
    return months <= 0 ? 0 : months;
}

function monthDiff(d1, d2) {
    var months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months -= d1.getMonth();
    months += d2.getMonth();
    return months <= 0 ? 0 : months;
}

function test(d1, d2) {
    var diff = monthDiff(d1, d2);
    console.log(
        d1.toISOString().substring(0, 10),
        "to",
        d2.toISOString().substring(0, 10),
        ":",
        diff
    );
}

test(
    new Date(2008, 10, 4), // November 4th, 2008
    new Date(2010, 2, 12)  // March 12th, 2010
);
// Result: 16

test(
    new Date(2010, 0, 1),  // January 1st, 2010
    new Date(2010, 2, 12)  // March 12th, 2010
);
// Result: 2

test(
    new Date(2010, 1, 1),  // February 1st, 2010
    new Date(2010, 2, 12)  // March 12th, 2010
);
// Result: 1

(Note that month values in JavaScript start with 0 = January.)

(请注意 JavaScript 中的月份值以 0 = 一月开始。)

Including fractional months in the above is much more complicated, because three days in a typical February is a larger fraction of that month (~10.714%) than three days in August (~9.677%), and of course even February is a moving target depending on whether it's a leap year.

在上面包含小数月份要复杂得多,因为典型的 2 月份的三天(~10.714%)比八月份的三天(~9.677%)要大得多,当然即使是 2 月份也是一个移动目标要看是不是闰年。

There are also some date and time librariesavailable for JavaScript that probably make this sort of thing easier.

也有一些可用于 JavaScript 的日期和时间库可能会使这类事情变得更容易。



Note: There used to be a + 1in the above, here:

注意:上面曾经有一个+ 1,这里:

months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth() + 1;
// ????????????????????^^^^
months += d2.getMonth();

That's because originally I said:

那是因为我最初说:

...this finds out how many full monthslie between two dates, not counting partial months (e.g., excluding the month each date is in).

...这会找出两个日期之间有多少完整的月份,不计算部分月份(例如,不包括每个日期所在的月份)。

I've removed it for two reasons:

我删除它有两个原因:

  1. Not counting partial months turns out not to be what many (most?) people coming to the answer want, so I thought I should separate them out.

  2. It didn't always work even by that definition. :-D (Sorry.)

  1. 不计算部分月份的结果并不是很多(大多数?)来回答的人想要的,所以我想我应该把它们分开。

  2. 即使按照这个定义,它也并不总是有效。:-D (对不起。)

回答by Tom Gullen

If you do not consider the day of the month, this is by far the simpler solution

如果您不考虑月份中的哪一天,这是迄今为止更简单的解决方案

function monthDiff(dateFrom, dateTo) {
 return dateTo.getMonth() - dateFrom.getMonth() + 
   (12 * (dateTo.getFullYear() - dateFrom.getFullYear()))
}


//examples
console.log(monthDiff(new Date(2000, 01), new Date(2000, 02))) // 1
console.log(monthDiff(new Date(1999, 02), new Date(2000, 02))) // 12 full year
console.log(monthDiff(new Date(2009, 11), new Date(2010, 0))) // 1

Be aware that month index is 0-based. This means that January = 0and December = 11.

请注意,月份索引是从 0 开始的。这意味着January = 0December = 11

回答by Mikayil Abdullayev

Sometimes you may want to get just the quantity of the months between two dates totally ignoring the day part. So for instance, if you had two dates- 2013/06/21 and 2013/10/18- and you only cared about the 2013/06 and 2013/10 parts, here are the scenarios and possible solutions:

有时您可能只想获得两个日期之间的月份数量,而完全忽略日期部分。因此,例如,如果您有两个日期 - 2013/06/21 和 2013/10/18- 并且您只关心 2013/06 和 2013/10 部分,以下是场景和可能的解决方案:

var date1=new Date(2013,5,21);//Remember, months are 0 based in JS
var date2=new Date(2013,9,18);
var year1=date1.getFullYear();
var year2=date2.getFullYear();
var month1=date1.getMonth();
var month2=date2.getMonth();
if(month1===0){ //Have to take into account
  month1++;
  month2++;
}
var numberOfMonths; 

1.If you want just the number of the months between the two dates excluding both month1 and month2

1.如果你只想要两个日期之间的月数,不包括month1和month2

numberOfMonths = (year2 - year1) * 12 + (month2 - month1) - 1;

2.If you want to include either of the months

2.如果你想包括任何一个月

numberOfMonths = (year2 - year1) * 12 + (month2 - month1);

3.If you want to include both of the months

3.如果你想包括这两个月份

numberOfMonths = (year2 - year1) * 12 + (month2 - month1) + 1;

回答by Francisc

Here's a function that accurately provides the number of months between 2 dates.
The default behavior only counts whole months, e.g. 3 months and 1 day will result in a difference of 3 months. You can prevent this by setting the roundUpFractionalMonthsparam as true, so a 3 month and 1 day difference will be returned as 4 months.

这是一个准确提供两个日期之间的月数的函数。
默认行为仅计算整月,例如 3 个月和 1 天将导致 3 个月的差异。您可以通过将roundUpFractionalMonthsparam设置为 来防止这种情况true,因此 3 个月和 1 天的差异将作为 4 个月返回。

The accepted answer above (T.J. Crowder's answer) isn't accurate, it returns wrong values sometimes.

上面接受的答案(TJ Crowder 的答案)不准确,它有时会返回错误的值。

For example, monthDiff(new Date('Jul 01, 2015'), new Date('Aug 05, 2015'))returns 0which is obviously wrong. The correct difference is either 1 whole month or 2 months rounded-up.

例如,monthDiff(new Date('Jul 01, 2015'), new Date('Aug 05, 2015'))返回0显然是错误的。正确的差异是 1 整月或 2 个月四舍五入。

Here's the function I wrote:

这是我写的函数:

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

回答by harun

If you need to count full months, regardless of the month being 28, 29, 30 or 31 days. Below should work.

如果您需要计算整月,无论该月是 28、29、30 还是 31 天。下面应该工作。

var months = to.getMonth() - from.getMonth() 
    + (12 * (to.getFullYear() - from.getFullYear()));

if(to.getDate() < from.getDate()){
    months--;
}
return months;

This is an extended version of the answer https://stackoverflow.com/a/4312956/1987208but fixes the case where it calculates 1 month for the case from 31st of January to 1st of February (1day).

这是答案https://stackoverflow.com/a/4312956/1987208的扩展版本,但修复了从 1 月 31 日到 2 月 1 日(1 天)计算 1 个月的情况。

This will cover the following;

这将涵盖以下内容;

  • 1st Jan to 31st Jan ---> 30days ---> will result in 0 (logical since it is not a full month)
  • 1st Feb to 1st Mar ---> 28 or 29 days ---> will result in 1 (logical since it is a full month)
  • 15th Feb to 15th Mar ---> 28 or 29 days ---> will result in 1 (logical since a month passed)
  • 31st Jan to 1st Feb ---> 1 day ---> will result in 0 (obvious but the mentioned answer in the post results in 1 month)
  • 1 月 1 日至 1 月 31 日 ---> 30 天 ---> 将导致 0(合乎逻辑,因为它不是整月)
  • 2 月 1 日至 3 月 1 日 ---> 28 或 29 天 ---> 将导致 1(合乎逻辑,因为它是整月)
  • 2 月 15 日至 3 月 15 日 ---> 28 或 29 天 ---> 将导致 1(自一个月过去以来的逻辑)
  • 1 月 31 日至 2 月 1 日 ---> 1 天 ---> 将导致 0(很明显,但帖子中提到的答案会在 1 个月内产生结果)

回答by harun

Difference in Months between two dates in JavaScript:

JavaScript 中两个日期之间的月差:

 start_date = new Date(year, month, day); //Create start date object by passing appropiate argument
 end_date = new Date(new Date(year, month, day)

total months between start_date and end_date :

start_date 和 end_date 之间的总月数:

 total_months = (end_date.getFullYear() - start_date.getFullYear())*12 + (end_date.getMonth() - start_date.getMonth())

回答by James

I know this is really late, but posting it anyway just in case it helps others. Here is a function I came up with that seems to do a good job of counting differences in months between two dates. It is admittedly a great deal raunchier than Mr.Crowder's, but provides more accurate results by stepping through the date object. It is in AS3 but you should just be able to drop the strong typing and you'll have JS. Feel free to make it nicer looking anyone out there!

我知道这真的很晚了,但还是发布它以防万一它可以帮助其他人。这是我想出的一个函数,它似乎可以很好地计算两个日期之间的月份差异。诚然,它比 Mr.Crowder 的更粗俗,但通过逐步遍历日期对象提供更准确的结果。它在 AS3 中,但您应该能够放弃强类型,并且您将拥有 JS。随意让它更好看任何人!

    function countMonths ( startDate:Date, endDate:Date ):int
    {
        var stepDate:Date = new Date;
        stepDate.time = startDate.time;
        var monthCount:int;

        while( stepDate.time <= endDate.time ) { 
            stepDate.month += 1;
            monthCount += 1;
        }           

        if ( stepDate != endDate ) { 
            monthCount -= 1;
        }

        return monthCount;
    }

回答by internet-nico

Consider each date in terms of months, then subtract to find the difference.

以月为单位考虑每个日期,然后减去以找出差异。

var past_date = new Date('11/1/2014');
var current_date = new Date();

var difference = (current_date.getFullYear()*12 + current_date.getMonth()) - (past_date.getFullYear()*12 + past_date.getMonth());

This will get you the difference of months between the two dates, ignoring the days.

这将为您提供两个日期之间的月差,忽略天数。

回答by Michael Blackburn

There are two approaches, mathematical & quick, but subject to vagaries in the calendar, or iterative & slow, but handles all the oddities (or at least delegates handling them to a well-tested library).

有两种方法,数学的和快速的,但受日历中的变幻莫测,或者迭代和缓慢,但处理所有奇怪的事情(或至少代表处理它们到经过良好测试的库)。

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 IFyou'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 onecalculation, the performance difference really is negligible. We tend to try to over-optimize tasks which will only be performed once.

如果您遍历日历,将开始日期增加一个月并查看我们是否超过了结束日期。这将异常处理委托给内置的 Date() 类,但如果您要为大量日期执行此操作,则可能会很慢。詹姆斯的回答采用了这种方法。尽管我不喜欢这个想法,但我认为这是“最安全”的方法,如果你只做一个计算,性能差异真的可以忽略不计。我们倾向于尝试过度优化只会执行一次的任务。

Now, ifyou're calculating this function on a dataset, you probably don't want to run that function on each row (or god forbid, multiple times per record). In that case, you can use almost any of the other answers here exceptthe accepted answer, which is just wrong (difference between new Date()and new Date()is -1)?

现在,如果您在数据集上计算此函数,您可能不想在每一行上运行该函数(或者上帝保佑,每条记录多次)。在这种情况下,除了接受的答案之外,您几乎可以在这里使用任何其他答案,这是错误的(new Date()和之间的差new Date()为 -1)?

Here's my stab at a mathematical-and-quick approach, which accounts for differing month lengths and leap years. You really should only use a function like this if you'll be applying this to a dataset (doing this calculation over & over). If you just need to do it once, use James' iterative approach above, as you're delegating handling all the (many) exceptions to the Date() object.

这是我对数学和快速方法的尝试,它解释了不同的月份长度和闰年。如果您要将其应用于数据集(反复进行此计算),您真的应该只使用这样的函数。如果您只需要执行一次,请使用上面 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;
}

回答by calvin

To expand on @T.J.'s answer, if you're looking for simple months, rather than full calendar months, you could just check if d2's date is greater than or equal to than d1's. That is, if d2 is later in its month than d1 is in its month, then there is 1 more month. So you should be able to just do this:

为了扩展@TJ 的答案,如果您正在寻找简单的月份,而不是完整的日历月份,您只需检查 d2 的日期是否大于或等于 d1 的日期。也就是说,如果 d2 在其月份中晚于 d1 在其月份中,则还有 1 个月。所以你应该能够做到这一点:

function monthDiff(d1, d2) {
    var months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months -= d1.getMonth() + 1;
    months += d2.getMonth();
    // edit: increment months if d2 comes later in its month than d1 in its month
    if (d2.getDate() >= d1.getDate())
        months++
    // end edit
    return months <= 0 ? 0 : months;
}

monthDiff(
    new Date(2008, 10, 4), // November 4th, 2008
    new Date(2010, 2, 12)  // March 12th, 2010
);
// Result: 16; 4 Nov – 4 Dec '08, 4 Dec '08 – 4 Dec '09, 4 Dec '09 – 4 March '10

This doesn't totally account for time issues (e.g. 3 March at 4:00pm and 3 April at 3:00pm), but it's more accurate and for just a couple lines of code.

这并不能完全解决时间问题(例如,3 月 3 日下午 4:00 和 4 月 3 日下午 3:00),但它更准确,并且只需要几行代码。