Qual è il modo migliore per determinare il numero di giorni in un mese con JavaScript?


107

Sto usando questa funzione ma mi piacerebbe sapere qual è il modo più efficiente e accurato per ottenerla.

function daysInMonth(iMonth, iYear) {
   return 32 - new Date(iYear, iMonth, 32).getDate();
}

Risposte:


200

function daysInMonth (month, year) { // Use 1 for January, 2 for February, etc.
  return new Date(year, month, 0).getDate();
}

console.log(daysInMonth(2, 1999)); // February in a non-leap year.
console.log(daysInMonth(2, 2000)); // February in a leap year.

Il giorno 0 è l'ultimo giorno del mese precedente. Poiché il costruttore del mese è basato su 0, funziona bene. Un po 'un trucco, ma fondamentalmente è quello che stai facendo sottraendo 32.


42
questa sintassi mi ha confuso per un po '. Per seguire il modello JS ti consiglio di implementare il trucco in questo modo:return new Date(year, month + 1, 0).getDate();
fguillen

2
Sfortunatamente ciò non riesce per le date precedenti al 1000 d.C. in cui è possibile impostare correttamente solo l'anno utilizzando SetFullYear (). Per renderlo a prova di proiettile usa la nuova data (2000+ (anno% 2000), mese, 0) .getDate ()
Noel Walters,

4
Nota per il mio io futuro: l'equazione di fguillen con il '+ 1' fornisce 28 giorni quando l'anno è il 2014 e il mese è 1 (che, in JavaScript Date-object, significa febbraio). Probabilmente voglio andare con quello per il minimo stupore. Ma che bella idea da FlySwat!
Harry Pehkonen

@ NoelWalters: hai ragione sul fatto che alcuni browser convertono in modo non corretto anni a due cifre in date del 20 ° secolo (quindi date prima del 100 d.C., non del 1000 d.C.), tuttavia la tua correzione non la rettifica in quei browser. L'unico modo per impostare in modo affidabile anni a due cifre è quello di utilizzare setFullYear : var d=new Date();d.setFullYear(year, month, date);.
RobG

1
E se monthè 12 ? Il Datecostruttore non dovrebbe assumere un valore compreso tra 0 e 11 ?
anddero

8

Se chiami spesso questa funzione, può essere utile memorizzare il valore nella cache per ottenere prestazioni migliori.

Ecco la versione di memorizzazione nella cache della risposta di FlySwat :

var daysInMonth = (function() {
    var cache = {};
    return function(month, year) {
        var entry = year + '-' + month;

        if (cache[entry]) return cache[entry];

        return cache[entry] = new Date(year, month, 0).getDate();
    }
})();

6
La routine C / C ++ interna è così lenta da richiedere la memorizzazione nella cache?
Pete Alvin

1
@PeteAlvin Dipende dall'implementazione di Date(quindi non esiste una risposta universale a questa domanda) e dalla frequenza con cui il tuo codice chiamerà dayInMonthcon gli stessi valori. Quindi l'unica risposta sensata è: profila il tuo codice e confrontalo!
dolmen

1
Mi piace! Ma invece di usare un nuovo oggetto cache, io uso localStorage.
andrew

5

Alcune risposte (anche su altre domande) avevano problemi con l'anno bisestile o utilizzavano l'oggetto Date. Sebbene javascript Date objectcopra circa 285616 anni (100.000.000 giorni) su entrambi i lati del 1 gennaio 1970, ero stufo di tutti i tipi di incongruenze di date inaspettate tra browser diversi (in particolare dall'anno 0 a 99). Ero anche curioso di sapere come calcolarlo.

Così ho scritto un semplice e, soprattutto, piccolo algoritmo per calcolare la corretta ( prolettico Gregoriana / astronomici / ISO 8601: 2004 (clausola 4.3.2.1), in modo da anno0 esiste ed è un anno bisestile e sono supportati anni negativi ) il numero dei giorni di per un dato mese e anno.
Utilizza l' algoritmo bitmask-modulo leapYear di cortocircuito (leggermente modificato per js) e l'algoritmo comune mod-8 mesi.

Notare che in AD/BCnotazione, l'anno 0 d.C. / BC non esiste: invece l'anno 1 BCè l'anno bisestile!
SE è necessario tenere conto della notazione BC, sottrarre prima un anno dal valore dell'anno (altrimenti positivo) !! (Oppure sottrai l'anno da 1per ulteriori calcoli annuali.)

function daysInMonth(m, y){
  return m===2?y&3||!(y%25)&&y&15?28:29:30+(m+(m>>3)&1);
}
<!-- example for the snippet -->
<input type="text" value="enter year" onblur="
  for( var r='', i=0, y=+this.value
     ; 12>i++
     ; r+= 'Month: ' + i + ' has ' + daysInMonth(i, y) + ' days<br>'
     );
  this.nextSibling.innerHTML=r;
" /><div></div>

Nota, i mesi devono essere basati su 1!

Nota, questo è un algoritmo diverso, quindi la ricerca del numero magico che ho usato nel mio Javascript calcola la risposta del giorno dell'anno (1 - 366) , perché qui il ramo extra per l'anno bisestile è necessario solo per febbraio.


4

Per eliminare la confusione, probabilmente creerei la stringa del mese in quanto è attualmente basata su 1.

function daysInMonth(month,year) {
    monthNum =  new Date(Date.parse(month +" 1,"+year)).getMonth()+1
    return new Date(year, monthNum, 0).getDate();
}

daysInMonth('feb', 2015)
//28

daysInMonth('feb', 2008)
//29

4

Con moment.js puoi usare il metodo daysInMonth ():

moment().daysInMonth(); // number of days in the current month
moment("2012-02", "YYYY-MM").daysInMonth() // 29
moment("2012-01", "YYYY-MM").daysInMonth() // 31

2

Ecco va

new Date(2019,2,0).getDate(); //28
new Date(2020,2,0).getDate(); //29

2

Sintassi ES6

const d = (y, m) => new Date(y, m, 0).getDate();

ritorna

console.log( d(2020, 2) );
// 29

console.log( d(2020, 6) );
// 30

1
Quando si aggiunge una nuova risposta a una domanda precedente con 14 risposte esistenti, è molto importante notare quale nuovo aspetto della domanda risponde alla propria risposta. È solo la sintassi ES6?
Jason Aller,

fatto. aggiungerà contesto alla risposta d'ora in poi.
RASG

1
function numberOfDays(iMonth, iYear) {
         var myDate = new Date(iYear, iMonth + 1, 1);  //find the fist day of next month
         var newDate = new Date(myDate - 1);  //find the last day
            return newDate.getDate();         //return # of days in this month
        }

1

Considerando gli anni bisestili:

function (year, month) {
    var isLeapYear = ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);

    return [31, (isLeapYear ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
}

Bello. Facile da guardare. Prop [ertie] s per l'uso di un valore inline-map / con chiave immediata.
Cody

1

Calcolo diretto di una riga (nessun oggetto Date):

function daysInMonth(m, y) {//m is 1-based, feb = 2
   return 31 - (--m ^ 1? m % 7 & 1:  y & 3? 3: y % 25? 2: y & 15? 3: 2);
}

console.log(daysInMonth(2, 1999)); // February in a non-leap year
console.log(daysInMonth(2, 2000)); // February in a leap year

Variazione con mesi a base 0:

function daysInMonth(m, y) {//m is 0-based, feb = 1
   return 31 - (m ^ 1? m % 7 & 1:  y & 3? 3: y % 25? 2: y & 15? 3: 2);
}

1

Se desideri il numero di giorni nel mese corrente di un oggetto Date, considera il metodo seguente:

Date.prototype.getNumberOfDaysInMonth = function(monthOffset) {
    if (monthOffset !== undefined) {
        return new Date(this.getFullYear(), this.getMonth()+monthOffset, 0).getDate();
    } else {
        return new Date(this.getFullYear(), this.getMonth(), 0).getDate();
    }
}

Quindi puoi eseguirlo in questo modo:

var myDate = new Date();
myDate.getNumberOfDaysInMonth(); // Returns 28, 29, 30, 31, etc. as necessary
myDate.getNumberOfDaysInMonth(); // BONUS: This also tells you the number of days in past/future months!

1

In una sola riga:

// month is 1-12
function getDaysInMonth(year, month){
    return month == 2 ? 28 + (year % 4 == 0 ? (year % 100 == 0 ? (year % 400 == 0 ? 1 : 0) : 1):0) : 31 - (month - 1) % 7 % 2;
}

1

Potrebbe essere un po 'eccessivo rispetto alla risposta selezionata :) Ma eccolo:

function getDayCountOfMonth(year, month) {
  if (month === 3 || month === 5 || month === 8 || month === 10) {
    return 30;
  }

  if (month === 1) {
    if (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0) {
      return 29;
    } else {
      return 28;
    }
  }

  return 31;
};

console.log(getDayCountOfMonth(2020, 1));

Ho trovato il codice sopra qui: https://github.com/ElemeFE/element/blob/dev/src/utils/date-util.js

function isLeapYear(year) { 
  return ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0); 
};

const getDaysInMonth = function (year, month) {
  return [31, (isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
};

console.log(getDaysInMonth(2020, 1));

Ho trovato il codice sopra qui: https://github.com/datejs/Datejs/blob/master/src/core.js


1

Se hai intenzione di passare una variabile di data, questo può essere utile

const getDaysInMonth = date =>
  new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();

daysInThisMonth = getDaysInMonth(new Date());

console.log(daysInThisMonth);


-1

Forse non la soluzione più elegante, ma di facile comprensione e manutenzione; ed è testato in battaglia.

function daysInMonth(month, year) {
    var days;
    switch (month) {
        case 1: // Feb, our problem child
            var leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
            days = leapYear ? 29 : 28;
            break;
        case 3: case 5: case 8: case 10: 
            days = 30;
            break;
        default: 
            days = 31;
        }
    return days;
},
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.