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

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

Любая помощь будет большой:)

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

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

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

Это расширенная версия ответа fooobar.com/questions/68073/..., но исправляет случай, когда он вычисляет 1 месяц для случая с 31 января по 1 февраля (1день).

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

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

Ответ 5

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

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

Например, 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);
};

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

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

Ответ 9

Развернуть на @T.J. ответьте, если вы ищете простые месяцы, а не полные календарные месяцы, вы можете просто проверить, превышает ли d2 дату или значение, чем d1. То есть, если d2 позже в месяце, чем d1 в месяце, то еще месяц. Поэтому вы должны просто сделать это:

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

Ответ 10

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

Если вы выполните итерацию по календарю, увеличив начальную дату на один месяц и посмотрев, пройдем ли дата окончания. Это делегирует обработку аномалий во встроенные классы 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;
}

Ответ 11

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

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

Ответ 12

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

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

Ответ 13

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

Ответ 14

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


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

Например:
date1: 24/09/2015 (24 сентября 2015 г.)
date2: 09/11/2015 (9 ноября 2015 г.)
разница: 2,5 (месяцы)

Ответ 15

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

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

Ответ 16

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;

}

Ответ 17

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

(endDate.getFullYear()*12+endDate.getMonth())-(startDate.getFullYear()*12+startDate.getMonth())

Ответ 18

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

Ответ 19

anyVar = (((DisplayTo.getFullYear() * 12) + DisplayTo.getMonth()) - ((DisplayFrom.getFullYear() * 12) + DisplayFrom.getMonth()));

Ответ 20

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

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

Ответ 21

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

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 

Ответ 22

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

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

const monthsLeft = moment(endDate).diff(moment(startDate), 'month');

Ответ 23

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

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

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

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

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

Ответ 24

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

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

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

Это предполагает, что ваш задний конец находится в Java.