Pergunta

Como eu resolveria a diferença para dois objetos DATE () em JavaScript, enquanto retornaria apenas o número de meses na diferença?

Qualquer ajuda seria ótimo :)

Foi útil?

Solução

A definição de "o número de meses na diferença" está sujeita a muita interpretação. :-)

Você pode obter o ano, mês e dia do mês a partir de um objeto JavaScript Data. Dependendo das informações que você está procurando, você pode usá -las para descobrir quantos meses estão entre dois pontos no tempo.

Por exemplo, fora do punho, isso descobre quantos meses completos mentira entre duas datas, sem contar meses parciais (por exemplo, excluindo o mês em que a data está dentro):

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

(Observe que os valores do mês em JavaScript começam com 0 = janeiro.)

Incluir meses fracionários no exposto é muito mais complicado, porque três dias em um típico de fevereiro é uma fração maior desse mês (~ 10,714%) do que três dias em agosto (~ 9,677%) e, é claro, até fevereiro é um alvo em movimento Dependendo se é um ano bissexto.

Há também alguns Bibliotecas de data e hora Disponível para JavaScript que provavelmente facilita esse tipo de coisa.

Outras dicas

Se você não considera o dia do mês, essa é de longe a solução mais simples

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

Esteja ciente que o índice do mês é baseado em 0. Isso significa que January = 0 e December = 11.

Às vezes, você pode querer obter apenas a quantidade dos meses entre duas datas ignorando totalmente a parte do dia. Por exemplo, se você teve duas datas- 2013/06/21 e 2013/10/18- e só se importava com as partes 2013/06 e 2013/10, aqui estão os cenários e possíveis soluções:

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.Se você deseja apenas o número dos meses entre as duas datas, excluindo o mês1 e o mês2

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

2. Se você deseja incluir um dos meses

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

3. Se você deseja incluir os dois meses

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

Aqui está uma função que fornece com precisão o número de meses entre 2 datas.
O comportamento padrão conta apenas meses inteiros, por exemplo, 3 meses e 1 dia resultarão em uma diferença de 3 meses. Você pode impedir isso definindo o roundUpFractionalMonths param como true, então uma diferença de 3 meses e 1 dia será devolvida em 4 meses.

A resposta aceita acima (a resposta de TJ Crowder) não é precisa, às vezes retorna valores errados.

Por exemplo, monthDiff(new Date('Jul 01, 2015'), new Date('Aug 05, 2015')) retorna 0 o que está obviamente errado. A diferença correta é 1 mês inteiro ou 2 meses arredondados.

Aqui está a função que escrevi:

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

Se você precisar contar meses completos, independentemente do mês de 28, 29, 30 ou 31 dias. Abaixo deve funcionar.

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

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

Esta é uma versão estendida da resposta https://stackoverflow.com/a/4312956/1987208 Mas corrige o caso em que ele calcula 1 mês para o caso de 31 de janeiro a 1º de fevereiro (1 dia).

Isso cobrirá o seguinte;

  • 1º de janeiro a 31 de janeiro ---> 30 dias ---> resultará em 0 (lógico, pois não é um mês inteiro)
  • 1º de fevereiro a 1º de março ---> 28 ou 29 dias ---> resultará em 1 (lógico, pois é um mês inteiro)
  • 15 de fevereiro a 15 de março ---> 28 ou 29 dias ---> resultará em 1 (lógico desde que um mês se passou)
  • 31 de janeiro a 1º de fevereiro ---> 1 dia ---> resultará em 0 (óbvio, mas a resposta mencionada nos resultados do post em 1 mês)

Diferença nos meses entre duas datas em 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)

Total de meses entre start_date e end_date:

 total_months = (end_date.getFullYear() - start_date.getFullYear())*12 + (end_date.getMonth() - start_date.getMonth())

Eu sei que isso é muito tarde, mas publicá -lo de qualquer maneira, caso isso ajude os outros. Aqui está uma função que eu criei que parece fazer um bom trabalho de contar diferenças nos meses entre duas datas. É reconhecidamente muito mais assustador que o de Sr. Crowder, mas fornece resultados mais precisos, passando pelo objeto da data. Está no AS3, mas você poderá ser capaz de soltar a digitação forte e terá JS. Sinta -se à vontade para torná -lo melhor olhando para alguém lá fora!

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

Considere cada data em termos de meses e subtraia para encontrar a diferença.

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

Isso lhe dará a diferença de meses entre as duas datas, ignorando os dias.

Para expandir a resposta de @TJ, se você estiver procurando meses simples, em vez de meses completos, você pode apenas verificar se a data do D2 é maior ou igual a D1. Ou seja, se o D2 estiver mais adiante no mês do que o D1 estiver em seu mês, há mais 1 mês. Então você deve ser capaz de fazer isso:

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

Isso não explica totalmente as questões de tempo (por exemplo, 3 de março às 16:00 e 3 de abril às 15:00), mas é mais preciso e para apenas algumas linhas de código.

Existem duas abordagens, matemáticas e rápidas, mas sujeitas a caprichos no calendário, ou iterativo e lento, mas lida com todas as esquisitices (ou pelo menos delega lidando com uma biblioteca bem testada).

Se você itera através do calendário, incrementando a data de início em um mês e vendo se passarmos a data de término. Isso delega de manuseio de anomalia para as classes embutidas da data (), mas pode ser lento E SE Você está fazendo isso por um grande número de datas. A resposta de James adota essa abordagem. Por mais que eu não goste da ideia, acho que essa é a abordagem "mais segura", e se você está apenas fazendo 1 Cálculo, a diferença de desempenho realmente é insignificante. Tendemos a tentar otimizar demais as tarefas que serão executadas apenas uma vez.

Agora, E se Você está calculando essa função em um conjunto de dados, provavelmente não deseja executar essa função em cada linha (ou Deus proíbe, várias vezes por registro). Nesse caso, você pode usar quase qualquer uma das outras respostas aqui exceto a resposta aceita, que está errada (diferença entre new Date() e new Date() é -1)?

Aqui está minha facada em uma abordagem matemática e rápida, que explica diferentes comprimentos de mês e anos bissextos. Você realmente deve usar apenas uma função como essa se estiver aplicando isso a um conjunto de dados (fazendo esse cálculo acima e sobre). Se você só precisar fazê -lo uma vez, use a abordagem iterativa de James acima, pois está delegando lidando com todas as (muitas) exceções ao objeto 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;
}

Aqui Você vai outra abordagem com menos loop:

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

Calcule a diferença entre duas datas inclui a fração do mês (dias).


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

Por exemplo:
Date1: 24/09/2015 (24 de setembro de 2015)
date2: 09/11/2015 (9 de novembro de 2015)
A diferença: 2,5 (meses)

Isso deve funcionar bem:

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

Você também pode considerar esta solução, este function Retorna a diferença de mês em número inteiro ou número

Passando pelo data de início Como o primeiro ou o último param, é tolerante a falhas. Ou seja, a função ainda retornaria o mesmo valor.

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

Seguindo o código retorna meses completos entre duas datas, levando em consideração a NR dos dias de meses parciais.

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;

}

Abaixo a lógica, buscará diferença nos meses

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

Veja o que eu uso:

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

Também conta os dias e os converte em meses.

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 

Para prosperidade,

Com Moment.js Você pode conseguir isso fazendo:

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

Uma abordagem seria escrever um serviço de web java simples (REST/JSON) que usa a biblioteca Joda

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

Para calcular a diferença entre duas datas e chamar esse serviço do JavaScript.

Isso pressupõe que seu back -end esteja em Java.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top