javascriptjquerydatedatejs

Getting the months between two dates


I'm not looking for an answer or code snippet to the question in the title, but rather I'm looking for help understanding why a snippet of code isn't working like I expect it to:

var getMonthsBetween = function(date1, date2)
{
    'use strict';

    // 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 start_date = date1;
    var end_date = date2;
    var inverse = false;

    if (date1 > date2)
    {
        start_date = date2;
        end_date = date1;
        inverse = true;
    }

    // Calculate the differences between the start and end dates
    var yearsDifference = end_date.getFullYear() - start_date.getFullYear();
    var monthsDifference = end_date.getMonth() - start_date.getMonth();
    var daysDifference = (end_date.getDate()+1) - start_date.getDate(); // This +1 might be a mistake  

    return (inverse ? -1 : 1) * (yearsDifference * 12 + monthsDifference + daysDifference/30); // Add fractional month
}

The above code is intended to return the difference (in months) between 2 given dates, accurate to the first decimal point. I didn't write the code myself and don't have contact with whoever did write it, unfortunately, and I can't tell why the author decided to add a day to the end date when working out the difference in days (there are instances where it is slightly off).

Could someone please help me with this problem? I'm not sure what the reason is to add that extra day here ((end_date.getDate()+1)) and I'm not sure it's actually correct (I suspect it's not correct) but I would like another opinion.

EDIT I was unclear about how the function is not working as expected - it is called as soon as the user selects 2 dates from 2 date pickers. The calculated numbers are not sent to the backend, instead the original 2 dates are sent back and then we use (PHP) datetime.diff to work out how many months there are between the dates. The backend has already been confirmed to be correct, but the frontend does not always match it, e.g.

start date = Monday June 30, 2014, 00:00:00
end date = Saturday February 28, 2015, 00:00:00
result (JS) = 7.933333333333334
result (PHP datetime.diff) = 8.0333333333333

or

start date = Tuesday June 30, 2015, 00:00:00
end date = Monday February 29, 2016, 00:00:00
result (JS) = 7.966666666666667
result (PHP datetime.diff) = 8.0333333333333

Then there are other times when the numbers do match e.g.

start date = Monday June 30, 2014, 00:00:00
end date = Wednesday April 15, 2015, 00:00:00
result (JS) = 9.5
result (PHP datetime.diff) = 9.5

Solution

  • Apparently PHP's datetime.diff includes the ending day in its calculation. When I actually incremented the end date on the JavaScript side, the numbers all match up. Incrementing the date object itself before comparing them accounts for changing to the next month. The original developer had noticed that that was happening, but he didn't increment the end date correctly. He added another day to the end date's day value, but that wasn't changing to the following month when adding a day to February 28, 2015

    This code works as expected:

    var getMonthsBetween = function(date1, date2)
    {
        'use strict';
    
        // 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 start_date = date1;
        var end_date = date2;
        var inverse = false;
    
        if (date1 > date2)
        {
            start_date = date2;
            end_date = date1;
            inverse = true;
        }
    
        end_date = new Date(end_date); //If you don't do this, the original date passed will be changed. Dates are mutable objects.
        end_date.setDate(end_date.getDate() + 1);
    
        // Calculate the differences between the start and end dates
        var yearsDifference = end_date.getFullYear() - start_date.getFullYear();
        var monthsDifference = end_date.getMonth() - start_date.getMonth();
        var daysDifference = end_date.getDate() - start_date.getDate();
    
        return (inverse ? -1 : 1) * (yearsDifference * 12 + monthsDifference + daysDifference/30); // Add fractional month
    }