Como calcularia a diferença para dois objetos Date () em JavaScript, enquanto retornava apenas o número de meses na diferença?
Qualquer ajuda seria ótimo :)
Como calcularia a diferença para dois objetos Date () em JavaScript, enquanto retornava apenas o número de meses na diferença?
Qualquer ajuda seria ótimo :)
Respostas:
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 de data JavaScript. Dependendo das informações que você está procurando, você pode usá-las para descobrir quantos meses existem entre dois pontos no tempo.
Por exemplo, fora do punho:
function monthDiff(d1, d2) {
var months;
months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth();
months += d2.getMonth();
return months <= 0 ? 0 : months;
}
(Observe que os valores do mês no JavaScript começam com 0 = janeiro.)
A inclusão de meses fracionários acima é muito mais complicada, porque três dias em fevereiro típico são uma fração maior desse mês (~ 10,714%) do que três dias em agosto (~ 9.677%) e, é claro, até fevereiro é uma meta em movimento dependendo se é um ano bissexto.
Existem também algumas bibliotecas de data e hora disponíveis para JavaScript que provavelmente facilitam esse tipo de coisa.
Nota : Havia um + 1
no acima, aqui:
months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth() + 1;
// −−−−−−−−−−−−−−−−−−−−^^^^
months += d2.getMonth();
Isso porque originalmente eu disse:
... descobre quantos meses completos estão entre duas datas, sem contar meses parciais (por exemplo, excluindo o mês em que cada data está).
Eu o removi por dois motivos:
Não contar meses parciais acaba não sendo o que muitas (a maioria?) Das pessoas que estão chegando à resposta querem, então pensei em separá-las.
Nem sempre funcionou mesmo com essa definição. :-D (Desculpe.)
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 de 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 de 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 se importou apenas com as partes 2013/06 e 2013/10, aqui estão os cenários e as 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 de meses entre as duas datas, excluindo mês1 e 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;
numberOfMonths=(year2-year1)*12+(month2-month1)+1;
o que faz o mesmo, mas é mais semanticamente correto para mim
Aqui está uma função que fornece com precisão o número de meses entre duas datas.
O comportamento padrão conta apenas meses inteiros, por exemplo, 3 meses e 1 dia resultará em uma diferença de 3 meses. Você pode evitar isso definindo o roundUpFractionalMonths
parâmetro como true
, portanto, uma diferença de 3 meses e 1 dia será retornada como 4 meses.
A resposta aceita acima (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'))
retornos 0
que estão obviamente errados. A diferença correta é de 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 inteiros, independentemente do mês ser 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 calcula 1 mês para o caso de 31 de janeiro a 1º de fevereiro (1 dia).
Isso cobrirá o seguinte;
Diferença de meses entre duas datas no 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 a data inicial e a data final:
total_months = (end_date.getFullYear() - start_date.getFullYear())*12 + (end_date.getMonth() - start_date.getMonth())
Eu sei que isso é muito tarde, mas postá-lo de qualquer maneira, apenas no caso de ajudar os outros. Aqui está uma função que eu criei que parece fazer um bom trabalho em contar diferenças em meses entre duas datas. É reconhecidamente muito mais atrevido que o de Mr.Crowder, mas fornece resultados mais precisos ao percorrer o objeto de data. Está no AS3, mas você deve ser capaz de abandonar a digitação forte e terá JS. Sinta-se livre para torná-lo melhor procurando 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;
}
Para expandir a resposta de @ TJ, se você estiver procurando meses simples, em vez de meses completos, basta verificar se a data de d2 é maior ou igual a d1. Ou seja, se d2 estiver no final do mês e d1 no mês, haverá mais 1 mês. Portanto, você deve conseguir 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 os problemas de horário (por exemplo, 3 de março às 16:00 e 3 de abril às 15:00), mas é mais preciso e apenas para algumas linhas de código.
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 fará a diferença de meses entre as duas datas, ignorando os dias.
Existem duas abordagens: matemática e rápida, mas sujeitas a caprichos no calendário, ou iterativas e lentas, mas lida com todas as esquisitices (ou pelo menos os delegados as tratam em uma biblioteca bem testada).
Se você percorrer o calendário, aumentando a data de início em um mês e ver se passamos a data de término. Isso delega o tratamento de anomalias para as classes internas Date (), mas pode ser lento se você estiver 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ê estiver fazendo apenas um cálculo, a diferença de desempenho é realmente insignificante. Tendemos a otimizar demais as tarefas que serão executadas apenas uma vez.
Agora, se você estiver calculando essa função em um conjunto de dados, provavelmente não deseja executar essa função em cada linha (ou seja, Deus não permita, 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 abordagem de uma abordagem matemática e rápida, responsável por diferentes comprimentos de meses e anos bissextos. Você realmente só deve usar uma função como essa se aplicá-la a um conjunto de dados (fazendo esse cálculo repetidamente). Se você precisar fazer isso apenas uma vez, use a abordagem iterativa de James acima, pois você está delegando o tratamento de 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ê segue 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;
}
Você também pode considerar esta solução, isso function
retorna a diferença do mês em número inteiro ou número
Passar a data de início como a primeira ou a última 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);
Calcular a diferença entre duas datas incluem 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;
}
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);
}
O código a seguir retorna meses completos entre duas datas, levando em consideração o número de dias dos 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 da lógica buscará diferença em 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
Nesse caso, não estou preocupado com meses inteiros, meses parciais, quanto tempo dura um mês etc. Eu só preciso saber o número de meses. Um caso relevante do mundo real seria onde um relatório deve ser entregue todos os meses, e eu preciso saber quantos relatórios devem existir.
Exemplo:
Este é um exemplo de código elaborado para mostrar para onde os números estão indo.
Vamos usar 2 carimbos de data e hora que devem resultar em 4 meses
Pode ser um pouco diferente com o fuso horário / horário estipulado. O dia, minutos e segundos não importam e podem ser incluídos no carimbo de data / hora, mas o desconsideraremos com nosso cálculo real.
let dateRangeStartConverted = new Date(1573621200000);
let dateRangeEndConverted = new Date(1582261140000);
let startingMonth = dateRangeStartConverted.getMonth();
let startingYear = dateRangeStartConverted.getFullYear();
let endingMonth = dateRangeEndConverted.getMonth();
let endingYear = dateRangeEndConverted.getFullYear();
Isso nos dá
(12 * (endYear - startYear)) + 1
ao mês final.2 + (12 * (2020 - 2019)) + 1 = 15
15 - 11 = 4
; nós obtemos nosso resultado de 4 meses.
De novembro de 2019 a março de 2022, são 29 meses. Se você as colocar em uma planilha do Excel, verá 29 linhas.
3 + (12 * (2022-2019)) + 1
40 - 11 = 29
anyVar = (((DisplayTo.getFullYear() * 12) + DisplayTo.getMonth()) - ((DisplayFrom.getFullYear() * 12) + DisplayFrom.getMonth()));
Uma abordagem seria escrever um Java Web Service 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 em javascript.
Isso pressupõe que seu back-end esteja em Java.