Quelle est la meilleure façon de déterminer le nombre de jours dans un mois avec JavaScript?

107

J'utilise cette fonction mais j'aimerais savoir quel est le moyen le plus efficace et le plus précis pour l'obtenir.

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

Réponses:

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.

Le jour 0 est le dernier jour du mois précédent. Étant donné que le constructeur du mois est basé sur 0, cela fonctionne bien. Un peu de hack, mais c'est essentiellement ce que vous faites en soustrayant 32.

FlySwat
la source
42
cette syntaxe me déroute depuis un moment. Pour suivre le modèle JS, je recommanderai d'implémenter l'astuce comme ceci:return new Date(year, month + 1, 0).getDate();
fguillen
2
Malheureusement, cela échoue pour les dates antérieures à 1000 après JC où vous ne pouvez définir correctement l'année qu'en utilisant SetFullYear (). Pour le rendre à l'épreuve des balles, utilisez new Date (2000+ (year% 2000), month, 0) .getDate ()
Noel Walters
4
Note à mon futur moi: l'équation de fguillen avec le '+ 1' donne 28 jours lorsque l'année est 2014 et le mois est 1 (ce qui, en JavaScript Date-objet, signifie février). Je veux probablement aller avec cela pour le moins d'étonnement. Mais quelle belle idée de FlySwat!
Harry Pehkonen
@ NoelWalters - vous avez raison de dire que certains navigateurs ne convertissent pas correctement les années à deux chiffres en dates du 20e siècle (donc des dates antérieures à 100 après JC, pas 1000 après JC), mais votre solution ne corrige pas cela dans ces navigateurs. La seule façon de deux ans de chiffre fiable est mis à utiliser setFullYear : var d=new Date();d.setFullYear(year, month, date);.
RobG
1
Que faire si monthest 12 ? Le Dateconstructeur ne devrait-il pas prendre une valeur de 0 à 11 ?
anddero
8

Si vous appelez souvent cette fonction, il peut être utile de mettre en cache la valeur pour de meilleures performances.

Voici la version de mise en cache de la réponse de 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();
    }
})();
dolmen
la source
6
La routine C / C ++ interne est-elle si lente que cela nécessite une mise en cache?
Pete Alvin
1
@PeteAlvin Cela dépend de l'implémentation de Date(il n'y a donc pas de réponse universelle à cette question) et de la fréquence à laquelle votre code appellera le dayInMonthavec les mêmes valeurs. La seule réponse raisonnable est donc: profilez votre code et comparez-le!
dolmen
1
Je l'aime! Mais au lieu d'utiliser un nouvel objet, cachej'utilise localStorage.
andrew
5

Certaines réponses (également sur d'autres questions) avaient des problèmes d'année bissextile ou utilisaient l'objet Date. Bien que le javascript Date objectcouvre environ 285616 ans (100 000 000 jours) de chaque côté du 1er janvier 1970, j'en avais marre de toutes sortes d' incohérences de date inattendues entre différents navigateurs (notamment les années 0 à 99). J'étais également curieux de savoir comment le calculer.

J'ai donc écrit un algorithme simple et surtout petit pour calculer le nombre correct ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (clause 4.3.2.1), donc l' année0 existe et est une année bissextile et les années négatives sont prises en charge ) le nombre de jours pour un mois et une année donnés.
Il utilise l' algorithme de court-circuit bitmask-modulo leapYear (légèrement modifié pour js) et l'algorithme commun mod-8 month.

Notez qu'en AD/BCnotation, l'année 0 AD / BC n'existe pas: à la place, l'année 1 BCest l'année bissextile!
SI vous devez tenir compte de la notation BC, soustrayez simplement une année de la valeur de l'année (sinon positive) en premier !! (Ou soustrayez l'année de 1pour d'autres calculs d'année.)

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>

Notez que les mois doivent être basés sur 1!

Notez qu'il s'agit d'un algorithme différent de la recherche de nombres magiques que j'ai utilisée dans mon Javascript pour calculer le jour de l'année (1 - 366) , car ici, la branche supplémentaire pour l'année bissextile n'est nécessaire que pour février.

GitaarLAB
la source
4

Pour éviter toute confusion, je créerais probablement la chaîne du mois en fonction de sa base actuelle.

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
Jaybeecave
la source
4

Avec moment.js, vous pouvez utiliser la méthode daysInMonth ():

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

C'est parti

new Date(2019,2,0).getDate(); //28
new Date(2020,2,0).getDate(); //29
Masum Billah
la source
2

Syntaxe ES6

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

Retour

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

console.log( d(2020, 6) );
// 30
RASG
la source
1
Lorsque vous ajoutez une nouvelle réponse à une question plus ancienne avec 14 réponses existantes, il est vraiment important de noter à quel nouvel aspect de la question votre réponse traite. Est-ce juste la syntaxe ES6?
Jason Aller
je l'ai. ajoutera du contexte à la réponse à partir de maintenant.
RASG le
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
        }
Tony Li
la source
1

Compte tenu des années bissextiles:

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];
}
Yash
la source
Agréable. Facile à regarder. Prop [ertie] s pour l'utilisation d'une valeur Inline-Map / Immediately-Keyed.
Cody le
1

Calcul direct à une ligne (pas d'objet 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

Variation avec les mois basés sur 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);
}
Tomas Langkaas
la source
1

Si vous voulez le nombre de jours dans le mois en cours d'un objet Date, envisagez la méthode suivante:

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

Ensuite, vous pouvez l'exécuter comme ceci:

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!
mrplants
la source
1

En une seule ligne:

// 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;
}
Shl
la source
1

Peut-être un peu trop tuer par rapport à la réponse sélectionnée :) Mais la voici:

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

J'ai trouvé le code ci-dessus ici: 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));

J'ai trouvé le code ci-dessus ici: https://github.com/datejs/Datejs/blob/master/src/core.js

Syed
la source
1

Si vous allez passer une variable de date, cela peut être utile

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

daysInThisMonth = getDaysInMonth(new Date());

console.log(daysInThisMonth);

sanka sanjeeva
la source
-1

Peut-être pas la solution la plus élégante, mais facile à comprendre et à maintenir; et, il est testé au combat.

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;
},
kmiklas
la source