Come potrei calcolare la differenza per due oggetti Date () in JavaScript, mentre restituirei solo il numero di mesi nella differenza?
Qualsiasi aiuto sarebbe grande :)
Come potrei calcolare la differenza per due oggetti Date () in JavaScript, mentre restituirei solo il numero di mesi nella differenza?
Qualsiasi aiuto sarebbe grande :)
Risposte:
La definizione di "il numero di mesi nella differenza" è soggetta a molte interpretazioni. :-)
È possibile ottenere l'anno, il mese e il giorno del mese da un oggetto data JavaScript. A seconda delle informazioni che stai cercando, puoi usarle per capire quanti mesi sono tra due punti nel tempo.
Ad esempio, senza risvolto:
function monthDiff(d1, d2) {
var months;
months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth();
months += d2.getMonth();
return months <= 0 ? 0 : months;
}
(Nota che i valori del mese in JavaScript iniziano con 0 = gennaio.)
Includere mesi frazionari sopra è molto più complicato, perché tre giorni in un tipico febbraio sono una frazione maggiore di quel mese (~ 10,714%) rispetto a tre giorni in agosto (~ 9,677%), e ovviamente anche febbraio è un obiettivo mobile a seconda che si tratti di un anno bisestile.
Ci sono anche alcune librerie di data e ora disponibili per JavaScript che probabilmente rendono questo tipo di cose più semplice.
Nota : in precedenza c'era una + 1
a, qui:
months = (d2.getFullYear() - d1.getFullYear()) * 12;
months -= d1.getMonth() + 1;
// −−−−−−−−−−−−−−−−−−−−^^^^
months += d2.getMonth();
Questo perché originariamente ho detto:
... questo scopre quanti mesi interi si trovano tra due date, senza contare i mesi parziali (ad esempio, escluso il mese in cui si trova ciascuna data).
L'ho rimosso per due motivi:
Non contare mesi parziali risulta non essere ciò che molte (la maggior parte?) Persone vogliono arrivare alla risposta, quindi ho pensato di doverle separare.
Non ha sempre funzionato nemmeno con quella definizione. MrGreen (scusami.)
Se non consideri il giorno del mese, questa è di gran lunga la soluzione più semplice
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
Tenere presente che l'indice del mese è basato su 0. Questo significa che January = 0
e December = 11
.
A volte potresti voler ottenere solo la quantità di mesi tra due date ignorando totalmente la parte del giorno. Quindi, ad esempio, se hai avuto due date - 2013/06/21 e 2013/10 / 18- e ti importavi solo delle parti 2013/06 e 2013/10, ecco gli scenari e le possibili soluzioni:
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 si desidera solo il numero di mesi tra le due date esclusi mese1 e mese2
numberOfMonths = (year2 - year1) * 12 + (month2 - month1) - 1;
2.Se si desidera includere uno dei mesi
numberOfMonths = (year2 - year1) * 12 + (month2 - month1);
3.Se si desidera includere entrambi i mesi
numberOfMonths = (year2 - year1) * 12 + (month2 - month1) + 1;
numberOfMonths=(year2-year1)*12+(month2-month1)+1;
che fa lo stesso ma che è semanticamente più corretto per me
Ecco una funzione che fornisce con precisione il numero di mesi tra 2 date.
Il comportamento predefinito conta solo mesi interi, ad esempio 3 mesi e 1 giorno comporterà una differenza di 3 mesi. Puoi roundUpFractionalMonths
evitarlo impostando param come true
, quindi una differenza di 3 mesi e 1 giorno verrà restituita come 4 mesi.
La risposta accettata sopra (risposta di TJ Crowder) non è accurata, a volte restituisce valori errati.
Ad esempio, monthDiff(new Date('Jul 01, 2015'), new Date('Aug 05, 2015'))
restituisce 0
che è ovviamente sbagliato. La differenza corretta è di 1 mese intero o 2 mesi arrotondati per eccesso.
Ecco la funzione che ho scritto:
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 devi contare mesi interi, indipendentemente dal fatto che il mese sia di 28, 29, 30 o 31 giorni. Di seguito dovrebbe funzionare.
var months = to.getMonth() - from.getMonth()
+ (12 * (to.getFullYear() - from.getFullYear()));
if(to.getDate() < from.getDate()){
months--;
}
return months;
Questa è una versione estesa della risposta https://stackoverflow.com/a/4312956/1987208 ma risolve il caso in cui calcola 1 mese per il caso dal 31 gennaio al 1 febbraio (1 giorno).
Questo coprirà quanto segue;
Differenza in mesi tra due date in 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)
mesi totali tra start_date e end_date:
total_months = (end_date.getFullYear() - start_date.getFullYear())*12 + (end_date.getMonth() - start_date.getMonth())
So che è molto tardi, ma pubblicarlo comunque nel caso in cui aiuti gli altri. Ecco una funzione che mi è venuta in mente che sembra fare un buon lavoro nel contare le differenze in mesi tra due date. È certamente molto più raunchier di quello di Mr.Crowder, ma fornisce risultati più accurati esaminando l'oggetto data. È in AS3 ma dovresti essere in grado di eliminare la digitazione forte e avrai JS. Sentiti libero di rendere più bello guardare qualcuno là fuori!
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;
}
Per espandere la risposta di @ TJ, se stai cercando mesi semplici, piuttosto che mesi completi, puoi semplicemente verificare se la data di d2 è maggiore o uguale a di d1. Cioè, se d2 è più tardi nel suo mese di d1 è nel suo mese, allora c'è ancora 1 mese. Quindi dovresti essere in grado di fare solo questo:
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
Questo non tiene conto del totale dei problemi di tempo (ad es. 3 marzo alle 16:00 e 3 aprile alle 15:00), ma è più preciso e solo per un paio di righe di codice.
Considera ogni data in termini di mesi, quindi sottrai per trovare la differenza.
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());
Questo ti porterà la differenza di mesi tra le due date, ignorando i giorni.
Esistono due approcci, matematico e rapido, ma soggetto a capricci nel calendario, o iterativo e lento, ma gestisce tutte le stranezze (o almeno i delegati che le gestiscono in una libreria ben collaudata).
Se esegui l'iterazione del calendario, incrementando la data di inizio di un mese e vedendo se superiamo la data di fine. Ciò delega la gestione delle anomalie alle classi Date () integrate, ma potrebbe essere lenta se lo stai facendo per un gran numero di date. La risposta di James adotta questo approccio. Per quanto non mi piaccia l'idea, penso che questo sia l'approccio "più sicuro", e se stai facendo solo un calcolo, la differenza di prestazioni è davvero trascurabile. Tendiamo a cercare di ottimizzare i compiti che verranno eseguiti solo una volta.
Ora, se stai calcolando questa funzione su un set di dati, probabilmente non vorrai eseguire quella funzione su ogni riga (o dio non voglia, più volte per record). In tal caso, puoi utilizzare quasi tutte le altre risposte qui tranne la risposta accettata, che è semplicemente sbagliata (la differenza tra new Date()
e new Date()
è -1)?
Ecco la mia pugnalata a un approccio matematico e rapido, che spiega la diversa durata dei mesi e gli anni bisestili. Dovresti davvero usare una funzione come questa solo se la applichi a un set di dati (facendo questo calcolo più e più volte). Se hai solo bisogno di farlo una volta, usa l'approccio iterativo di James sopra, mentre stai delegando la gestione di tutte le (molte) eccezioni all'oggetto 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;
}
Ecco un altro approccio con meno 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;
}
Potresti anche considerare questa soluzione, questo function
restituisce la differenza del mese in numero intero o numero
Passare la data di inizio come la prima o l'ultima param
, è tollerante ai guasti. Significato, la funzione restituirà comunque lo stesso valore.
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);
Calcola la differenza tra due date includendo la frazione del mese (giorni).
var difference = (date2.getDate() - date1.getDate()) / 30 +
date2.getMonth() - date1.getMonth() +
(12 * (date2.getFullYear() - date1.getFullYear()));
Ad esempio:
data1 : 24/09/2015 (24 settembre 2015)
data2 : 09/11/2015 (9 novembre 2015)
differenza: 2,5 (mesi)
Questo dovrebbe funzionare bene:
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);
}
Il codice seguente restituisce mesi interi tra due date prendendo in considerazione anche il numero di giorni di mesi parziali.
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;
}
la logica seguente recupererà la differenza in mesi
(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;
}
Vedi cosa 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;
}
Conta anche i giorni e li converte in mesi.
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
In questo caso, non mi occupo di mesi interi, mesi parziali, quanto è lungo un mese, ecc. Devo solo conoscere il numero di mesi. Un caso rilevante nel mondo reale sarebbe quello in cui un rapporto dovrebbe essere presentato ogni mese e devo sapere quanti rapporti dovrebbero esserci.
Esempio:
Questo è un esempio di codice elaborato per mostrare dove stanno andando i numeri.
Prendiamo 2 timestamp che dovrebbero tradursi in 4 mesi
Potrebbe essere leggermente diverso con il fuso orario / tempo tirato. Il giorno, i minuti e i secondi non contano e possono essere inclusi nel timestamp, ma lo ignoreremo con il nostro calcolo effettivo.
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();
Questo ci dà
(12 * (endYear - startYear)) + 1
al mese finale.2 + (12 * (2020 - 2019)) + 1 = 15
15 - 11 = 4
; otteniamo il nostro risultato di 4 mesi.
Da novembre 2019 a marzo 2022 sono 29 mesi. Se li metti in un foglio di calcolo Excel, vedrai 29 righe.
3 + (12 * (2022-2019)) + 1
40-11 = 29
anyVar = (((DisplayTo.getFullYear() * 12) + DisplayTo.getMonth()) - ((DisplayFrom.getFullYear() * 12) + DisplayFrom.getMonth()));
Un approccio sarebbe quello di scrivere un semplice servizio Web Java (REST / JSON) che utilizza la libreria JODA
http://joda-time.sourceforge.net/faq.html#datediff
per calcolare la differenza tra due date e chiamare quel servizio da javascript.
Ciò presuppone che il back-end sia in Java.