views:

859

answers:

2

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

Any help would be great :)

+4  A: 

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.

For instance, off-the-cuff, this finds out how many full months lie between two dates, not counting partial months (e.g., excluding the month each date is in):

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

monthDiff(
    new Date(2008, 10, 4), // November 4th, 2008
    new Date(2010, 2, 12)  // March 12th, 2010
);
// Result: 15: December 2008, all of 2009, and Jan & Feb 2010

monthDiff(
    new Date(2010, 0, 1),  // January 1st, 2010
    new Date(2010, 2, 12)  // March 12th, 2010
);
// Result: 1: February 2010 is the only full month between them

monthDiff(
    new Date(2010, 1, 1),  // February 1st, 2010
    new Date(2010, 2, 12)  // March 12th, 2010
);
// Result: 0: There are no *full* months between them

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

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.

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

T.J. Crowder
Have +1 for nuance.
Jonathan Feinberg
@T.J.: +1 for your function, it's a good example of where the OP could start, but I would think that at least a "full" month should be counted for (e.g.) Feb 1st to March 31st :-)
Andy E
@Andy: Agreed, totally just a starting point. Re the full month between 2010/2/1 and 2010/3/31, aside from complicating things in a similar manner to fractional months, how would we handle 23:59:59 on 2010/2/1 to 00:00:01 on 2010/3/31? That's ~2 days short of a full month! ;-) Being thorough really would require a proper calendar, allowing for leap years, discontinuities (such as the Gregorian Adjustment in 1582), etc., since JavaScript Date objects can go backward about 285k years. But you can't really use JS Date objects for that sort of thing anyway, they don't handle leap seconds. :-)
T.J. Crowder
[geek_mode]Expanding on the Gregorian thing: JavaScript only uses an *extrapolated* Gregorian calendar and ignores leap seconds. This means, amongst other things, that any date prior to 15 October 1582 will be flat-out wrong when the year, month, or day are queried (such as when it's turned into a string), because JavaScript doesn't handle the Adjustment (the day before 15 October 1582 was 4 October 1582; there was no 5th through 14th that year).[/geek_mode]
T.J. Crowder
@T.J: Of course, as your answer stated it really depends on the OP's actual requirements. The only semi-viable solution I could think of involved iterating backwards over the second date parameter, checking for leap year and subtracting the number of days in the previous month from the date whilst increasing a var by 1 each time, then working out the fraction for the final month :-) I was even going to write it, but it's Monday morning and I haven't even had my coffee yet ;-) Re: [geek_mode] you really know your stuff!
Andy E
A: 

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!

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