Разница в месяцах между двумя датами в JavaScript - PullRequest
114 голосов
/ 29 марта 2010

Как бы я вычислил разницу для двух объектов Date () в JavaScript, при этом возвращая только количество месяцев в разнице?

Любая помощь будет великолепна:)

Ответы [ 24 ]

205 голосов
/ 29 марта 2010

Определение «количество месяцев в разнице» подлежит толкованию. : -)

Вы можете получить год, месяц и день месяца из объекта даты в JavaScript. В зависимости от того, какую информацию вы ищете, вы можете использовать ее, чтобы выяснить, сколько месяцев проходит между двумя моментами времени.

Например, вне манеры, это определяет, сколько полных месяцев лежит между двумя датами, не считая неполных месяцев (например, исключая месяц, в котором находится каждая дата):

function monthDiff(d1, d2) {
    var months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months -= d1.getMonth() + 1;
    months += d2.getMonth();
    return months <= 0 ? 0 : 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

(Обратите внимание, что значения месяца в JavaScript начинаются с 0 = января.)

Включение дробных месяцев в вышеприведенное намного сложнее, потому что три дня в типичном феврале - это большая доля этого месяца (~ 10,714%), чем три дня в августе (~ 9,677%), и, конечно, даже февраль движущаяся цель в зависимости от того, является ли это високосным годом.

Есть также некоторые библиотеки даты и времени , доступные для JavaScript, которые, вероятно, облегчают подобные вещи.

62 голосов
/ 30 ноября 2010

Если вы не считаете день месяца, это гораздо более простое решение

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

Имейте в виду, что индекс месяца основан на 0. Это означает, что January = 0 и December = 11.

28 голосов
/ 01 марта 2013

Иногда вы можете захотеть получить только количество месяцев между двумя датами, полностью игнорируя часть дня. Например, если у вас было две даты - 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.Если вы хотите указать количество месяцев между двумя датами, исключая месяц1 и месяц2

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

2. Если вы хотите включить один из месяцев

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

3.Если вы хотите включить оба месяца

numberOfMonths = (year2 - year1) * 12 + (month2 - month1) + 1;
22 голосов
/ 09 января 2014

Если вам необходимо сосчитать полные месяцы, независимо от того, какой месяц равен 28, 29, 30 или 31 дню. Ниже должно работать.

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

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

Это расширенная версия ответа https://stackoverflow.com/a/4312956/1987208, но исправляет случай, в котором он рассчитывает 1 месяц для случая с 31 января по 1 февраля (1 день).

Это будет охватывать следующее;

  • 1 января - 31 января ---> 30 дней ---> приведет к 0 (логично, так как это не полный месяц)
  • 1 февраля - 1 марта ---> 28 или 29 дней ---> приведет к 1 (логично, поскольку это полный месяц)
  • с 15 февраля по 15 марта ---> 28 или 29 дней ---> приведет к 1 (логично с прошедшего месяца)
  • 31 января - 1 февраля ---> 1 день ---> приведет к 0 (очевидно, но упомянутый ответ в сообщении приводит к 1 месяцу)
21 голосов
/ 14 ноября 2014

Вот функция, которая точно предоставляет количество месяцев между двумя датами.
Поведение по умолчанию учитывает только целые месяцы, например, 3 месяца и 1 день приведет к разнице в 3 месяца.Вы можете предотвратить это, установив для параметра roundUpFractionalMonths значение true, поэтому разница в 3 месяца и 1 день будет возвращена как 4 месяца.

Принятый ответ выше (ответ TJ Crowder) isnТочно, иногда он возвращает неправильные значения.

Например, 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);
};
7 голосов
/ 15 марта 2014

Разница в месяцах между двумя датами в 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)

общее количество месяцев между датой start_date и end_date:

 total_months = (end_date.getFullYear() - start_date.getFullYear())*12 + (end_date.getMonth() - start_date.getMonth())
6 голосов
/ 22 июля 2010

Я знаю, что это действительно поздно, но опубликовать его на всякий случай, если это поможет другим. Вот функция, которую я придумал, которая, кажется, хорошо справляется с подсчетом различий в месяцах между двумя датами. По общему признанию, он намного более грубый, чем у мистера Краудера, но дает более точные результаты, проходя через объект date Это в 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;
    }
5 голосов
/ 22 ноября 2015

Рассмотрите каждую дату в месяцах, затем вычтите, чтобы найти разницу.

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

Это даст вам разницу месяцев между двумя датами, игнорируя дни.

4 голосов
/ 27 февраля 2015

Существует два подхода: математический и быстрый, но подверженный капризам в календаре, или итеративный и медленный, но он обрабатывает все странности (или, по крайней мере, делегаты обрабатывают их в хорошо протестированной библиотеке).

Если вы выполняете итерацию по календарю, увеличивая дату начала на один месяц и просматривая, передаем ли мы дату окончания. Это делегирует обработку аномалий встроенным классам Date (), но может быть медленным IF вы делаете это для большого числа дат. Джеймс ответ принимает такой подход. Как бы мне не нравилась эта идея, я думаю, что это самый «безопасный» подход, и если вы выполняете только один расчет, разница в производительности действительно незначительна. Мы стремимся чрезмерно оптимизировать задачи, которые будут выполняться только один раз.

Теперь, если вы вычисляете эту функцию для набора данных, вы, вероятно, не хотите запускать эту функцию в каждой строке (или, не дай бог, несколько раз для каждой записи). В этом случае вы можете использовать почти любой другой ответ здесь , за исключением принятого ответа, который является просто неправильным (разница между new Date() и new Date() равна -1)?

Вот мой пример математического и быстрого подхода, который учитывает разную продолжительность месяца и високосного года. Вы действительно должны использовать функцию, подобную этой, только если вы будете применять ее к набору данных (делать это снова и снова). Если вам просто нужно сделать это один раз, используйте итерационный подход Джеймса выше, поскольку вы делегируете обработку всех (многих) исключений для объекта 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;
}
4 голосов
/ 19 марта 2014

Чтобы расширить ответ @ T.J., если вы ищете простые месяцы, а не полные календарные месяцы, вы можете просто проверить, является ли дата 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

Это не полностью учитывает проблемы времени (например, 3 марта в 16:00 и 3 апреля в 15:00), но это более точно и всего для пары строк кода.

...