Разница в месяцах между двумя датами в JavaScript

StackOverflow https://stackoverflow.com/questions/2536379

  •  22-09-2019
  •  | 
  •  

Вопрос

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

Любая помощь будет здорово :)

Это было полезно?

Решение

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

Вы можете получить год, месяц и день месяца из объекта даты 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, что, вероятно, упростит подобные вещи.

Другие советы

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

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.

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

Вот функция, которая точно определяет количество месяцев между двумя датами.
Поведение по умолчанию учитывает только целые месяцы, например.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);
};

Если вам нужно считать полные месяцы, независимо от того, сколько в месяце 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 месяц)

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

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

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

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

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

Чтобы расширить ответ @ 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), но это более точно и требует всего пары строк кода.

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

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

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

Здесь вы используете другой подход с меньшим количеством циклов:

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

Вычислите разницу между двумя датами, включая долю месяца (дней).


var difference = (date2.getDate() - date1.getDate()) / 30 +
    date2.getMonth() - date1.getMonth() +
    (12 * (date2.getFullYear() - date1.getFullYear()));

Например:
дата1:24.09.2015 (24 сентября 2015 г.)
дата2:11.09.2015 (9 ноября 2015 г.)
разница:2,5 (месяцев)

Это должно работать нормально:

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

Вы также можете рассмотреть это решение, это function возвращает разницу в месяцах в виде целого числа или числа

Прохождение Дата начала как первый или последний param, является отказоустойчивым.Это означает, что функция все равно будет возвращать то же значение.

const diffInMonths = (end, start) => {
   var timeDiff = Math.abs(end.getTime() - start.getTime());
   return Math.round(timeDiff / (2e3 * 3600 * 365.25));
}

const result = diffInMonths(new Date(2015, 3, 28), new Date(2010, 1, 25));

// shows month difference as integer/number
console.log(result);

function calcualteMonthYr(){
    var fromDate =new Date($('#txtDurationFrom2').val()); //date picker (text fields)
    var toDate = new Date($('#txtDurationTo2').val());

var months=0;
        months = (toDate.getFullYear() - fromDate.getFullYear()) * 12;
        months -= fromDate.getMonth();
        months += toDate.getMonth();
            if (toDate.getDate() < fromDate.getDate()){
                months--;
            }
    $('#txtTimePeriod2').val(months);
}

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

var monthDiff = function(d1, d2) {
  if( d2 < d1 ) { 
    var dTmp = d2;
    d2 = d1;
    d1 = dTmp;
  }

  var months = (d2.getFullYear() - d1.getFullYear()) * 12;
  months -= d1.getMonth() + 1;
  months += d2.getMonth();

  if( d1.getDate() <= d2.getDate() ) months += 1;

  return months;
}

monthDiff(new Date(2015, 01, 20), new Date(2015, 02, 20))
> 1

monthDiff(new Date(2015, 01, 20), new Date(2015, 02, 19))
> 0

monthDiff(new Date(2015, 01, 20), new Date(2015, 01, 22))
> 0
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;

}

логика ниже даст разницу в месяцах

(endDate.getFullYear()*12+endDate.getMonth())-(startDate.getFullYear()*12+startDate.getMonth())
function monthDiff(date1, date2, countDays) {

  countDays = (typeof countDays !== 'undefined') ?  countDays : false;

  if (!date1 || !date2) {
    return 0;
  }

  let bigDate = date1;
  let smallDate = date2;

  if (date1 < date2) {
    bigDate = date2;
    smallDate = date1;
  }

  let monthsCount = (bigDate.getFullYear() - smallDate.getFullYear()) * 12 + (bigDate.getMonth() - smallDate.getMonth());

  if (countDays && bigDate.getDate() < smallDate.getDate()) {
    --monthsCount;
  }

  return monthsCount;
}

Посмотрите, что я использую:

function monthDiff() {
    var startdate = Date.parseExact($("#startingDate").val(), "dd/MM/yyyy");
    var enddate = Date.parseExact($("#endingDate").val(), "dd/MM/yyyy");
    var months = 0;
    while (startdate < enddate) {
        if (startdate.getMonth() === 1 && startdate.getDate() === 28) {
            months++;
            startdate.addMonths(1);
            startdate.addDays(2);
        } else {
            months++;
            startdate.addMonths(1);
        }
    }
    return months;
}

Он также считает дни и конвертирует их в месяцы.

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 

Для процветания,

С Момент.js вы можете добиться этого, выполнив:

const monthsLeft = moment(endDate).diff(moment(startDate), 'month');
anyVar = (((DisplayTo.getFullYear() * 12) + DisplayTo.getMonth()) - ((DisplayFrom.getFullYear() * 12) + DisplayFrom.getMonth()));

Одним из подходов было бы написать простой веб-сервис Java (REST/JSON), использующий библиотеку JODA.

http://joda-time.sourceforge.net/faq.html#datediff

чтобы вычислить разницу между двумя датами и вызвать эту службу из JavaScript.

Предполагается, что ваша серверная часть находится на Java.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top