Nombre de jours par mois

Comment puis-je écrire une fonction JavaScript qui accepte un numéro de 1 à 12 représentant les mois de l'année, puis retourne le nombre de jours de ce mois?

function getDaysInMonth(m, y) { return /8|3|5|10/.test(--m)?30:m==1?(!(y%4)&&y%100)||!(y%400)?29:28:31; } 

Essaye ça:

 function numberOfDays(year, month) { var d = new Date(year, month, 0); return d.getDate(); } 

En raison des années bissextiles, vous devez passer l'année aussi.

Trente jours ont eu septembre,
Avril, juin et novembre;
Tout le reste a trente et un,
Sauf février seulement,
Ce qui a vingt-huit jours clair,
Et vingt-neuf dans chaque année bissextile.

<3 Wikipedia

J'ai adoré la réponse de James. Réformaté légèrement pour les personnes intéressées.

 function getDaysInMonth(m, y) { // months in JavaScript start at 0 so decrement by 1 eg 11 = Dec --m; // if month is Sept, Apr, Jun, Nov return 30 days if( /8|3|5|10/.test( m ) ) return 30; // if month is not Feb return 31 days if( m != 1 ) return 31; // To get this far month must be Feb ( 1 ) // if the year is a leap year then Feb has 29 days if( ( y % 4 == 0 && y % 100 != 0 ) || y % 400 == 0 ) return 29; // Not a leap year. Feb has 28 days. return 28; } 

Fiddle ici

Tout le monde sait que le fait de compter le sandwich à la mandrine de Chuck bat seulement de la poésie n'importe quel jour de la semaine .

Poing de Chuck Norris. Comptez le knucle.

Si vous ne pouvez pas obtenir cela pour compiler et exécuter (comme la poésie), lisez la suite.


Sans regex et moins 2 opérations de remplacement de module , également sans problèmes d'année bissextile ou Date-object.
Bien que l' Date object de javascript couvre environ 285616 ans (100 000 000 jours) de chaque côté du 1er janvier 1970, j'étais fatigué de toutes sortes d' incohérences inattendues de la date dans différents navigateurs (surtout l'année 0 à 99). J'étais aussi curieux de le calculer.

Donc, j'ai écrit un algorithme simple et, surtout, petit (répondant facilement à James) pour calculer le bon ( Proletrique Grégorien / Astronomique / ISO 8601: 2004 (clause 4.3.2.1), donc l' année 0 existe et est une année bissextile et négative Années sont prises en charge ) nombre de jours pour un mois et une année donné.
Il utilise l' algorithme de curseur bitmask-modulo leipYear (légèrement modifié pour js) et l'algorithme mod-8 mois courant (modifié à nouveau pour obtenir le chemin le plus court).

Notez que dans la notation AD/BC , l'année 0 AD / BC n'existe pas: plutôt que l'année 1 BC est l'année bissextile!
Si vous devez comptabiliser la notation BC, restez simplement une année de la valeur d'année (sinon positive) d'abord! (Ou soustraire l'année de 1 pour des calculs d'année supplémentaires.)

 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" placeholder="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> 

En termes informatiques, les new Date() solutions new Date() et d' regular expression sont lentes! Si vous voulez un super-rapide (et super-cryptique) one-liner, essayez celui-ci (en supposant que m est en Jan=1 format selon la question):

La seule concurrence réelle pour la vitesse est de @GitaarLab, donc j'ai créé un JSPerf tête-à-tête pour nous tester sur: http://jsperf.com/days-in-month-head-to-head/5

Je continue d'essayer différents changements de code pour obtenir les meilleures performances.

Version actuelle

Après avoir examiné cette question connexe, l' année de balbutiage utilisant des opérateurs bit à bit (vitesse incroyable) et la découverte de ce que représentaient les 25 et 15 numéros magiques, j'ai trouvé cette hybride optimisée de réponses:

 function getDaysInMonth(m, y) { return m===2 ? y & 3 || !(y % 25) && y & 15 ? 28 : 29 : 30 + (m +(m >> 3) & 1); } 

JSFiddle: http://jsfiddle.net/TrueBlueAussie/H89X3/22/

Résultats JSPerf: http://jsperf.com/days-in-month-head-to-head/5

Pour une raison quelconque, (m+(m>>3)&1) est plus efficace que (5546>>m&1) sur presque tous les navigateurs.


Versions précédentes:

Celui-ci a supprimé un seul ! Test en inversant les valeurs (légère augmentation):

 function getDaysInMonth(m, y) { return m === 2 ? (y % 4 || !(y % 100) && (y % 400)) ? 28 : 29 : 30 + (m + (m >> 3) & 1); } 

Celui-ci a supprimé les parenthèses inutiles:

 function getDaysInMonth2(m, y) { return m === 2 ? !(y % 4 || !(y % 100) && (y % 400)) ? 29 : 28 : 30 + (m + (m >> 3) & 1); } 

Celui-ci était descendu jusqu'à + étant un peu plus rapide que XOR ( ^ )

 function getDaysInMonth(m, y) { return (m === 2) ? (!((y % 4) || (!(y % 100) && (y % 400))) ? 29 : 28) : 30 + ((m + (m >> 3)) & 1); } 

C'était ma poitrine d'origine:

 function getDaysInMonth(m, y) { return m == 2 ? (!((y % 4) || (!(y % 100) && (y % 400))) ? 29 : 28) : (30 + ((m >> 3 ^ m) & 1)); } 

Il fonctionne en fonction de ma réponse de l'année bissextile ici: javascript pour trouver l'année bissextile, cette réponse ici , la vérification de l'année butoir en utilisant des opérateurs bit à bit (vitesse incroyable) ainsi que la logique binaire suivante.


Une leçon rapide en mois binaire:

Si vous interprétez l'index des mois souhaités (Jan = 1) en binaire, vous remarquerez que les mois avec 31 jours ont un bit 3 clair et un bit 0 réglé, ou le bit 3 est défini et le bit 0 est clair.

 Jan = 1 = 0001 : 31 days Feb = 2 = 0010 Mar = 3 = 0011 : 31 days Apr = 4 = 0100 May = 5 = 0101 : 31 days Jun = 6 = 0110 Jul = 7 = 0111 : 31 days Aug = 8 = 1000 : 31 days Sep = 9 = 1001 Oct = 10 = 1010 : 31 days Nov = 11 = 1011 Dec = 12 = 1100 : 31 days 

Cela signifie que vous pouvez déplacer la valeur 3 places avec >> 3 , XOR les bits avec l'original ^ m et voir si le résultat est 1 ou 0 en position de bit 0 en utilisant & 1 . Remarque: Il s'avère que + est légèrement plus rapide que XOR ( ^ ) et (m >> 3) + m donne le même résultat au bit 0.

Résultats JSPerf : http://jsperf.com/days-in-month-perf-test/6 (23 fois plus rapide que la réponse acceptée).


Mise à jour: J'ai passé une comparaison des deux meilleures réponses + dernières (@James, @Caleb & @GitaarLAB) contre celle-ci pour s'assurer qu'elles donnent des résultats cohérents et toutes les 4 renvoient les mêmes valeurs pour tous les mois dans toutes les années de l'année 1 à l'année 4000: http://jsfiddle.net/TrueBlueAussie/8Lmpnpz4/6/ . L'année 0 est la même pour tous sauf @Caleb.

Une autre mise à jour:

Si la vitesse absolue était le seul objectif, et cela ne vous dérange pas de perdre de la mémoire, puis le stockage des résultats pour une période donnée d'années, dans une table bidimensionnelle est probablement la manière la plus rapide possible:

 function DIM(m, y) { //TrueBlueAussie return m===2?(y%4||!(y%100)&&(y%400))?28:29:30+(m+(m>>3)&1); } array = new Array(4000); for (var y = 1; y < 4000; y++){ array[y] = []; for (var m = 1; m < 13; m++) { array[y][m] = DIM(m, y); } } // This just does a lookup into the primed table - wasteful, but fast function getDaysInMonth2(m, y){ return array[y][m]; } 

JSPerf: http://jsperf.com/days-in-month-head-to-head/5

Dans l'esprit de ne pas faire vos devoirs pour vous , je présente une version dans POVRay (désolé, pas JS) que j'ai fait il ya plusieurs années.

Dans POVRay, il n'y a pas de variables booléennes. La méthode que j'ai proposée était de créer un polynôme dans «m» qui a donné une réponse> 0 pendant des mois avec 31 jours et <0 pendant des mois avec 30 jours.

 #declare m0 = (m-0.5)*(m-1.5)*(m-2.5)*(m-3.5)*(m-4.5)*(m-5.5); #declare m0 = m0*(m-6.5)*(m-8.5)*(m-9.5)*(m-10.5)*(m-11.5); #if (m0 > 0) #declare maxdays = 31; #else #declare maxdays = 30; #end 

La partie délicate est de décider quand l'année est une année bissextile. C'est le test complet pour les années bissextiles. La plupart des gens sont conscients de la règle des 4 ans et, depuis 2000, certains connaissent les règles de 100 et 400 ans, il n'y a pas de règle de 4 000 ans.

 #declare LEAPYEAR = 2.0; #if (mod(YEAR,4.0)=0) #declare LEAPYEAR = 1.0; #if (mod(YEAR,100.0)=0) #declare LEAPYEAR = 2.0; #end #if (mod(YEAR,400.0)=0 #declare LEAPYEAR = 1.0; #end #end #if (MONTH = 2.0) #declare maxdays = maxdays - LEAPYEAR; #end #if (DAY > maxdays) #declare MONTH = MONTH + 1; #declare DAY = DAY - maxdays; #end #if (MONTH > 12) #declare YEAR = YEAR + 1; #declare MONTH = MONTH - 12; #end 

J'ai adoré la réponse de James ainsi que l'explication de Bruno. Cependant, a été ennuyé par la nature excessivement cryptique de la solution. Donc, voici la même solution, mais nettoyé tout cryptage inutile.

 function getDaysInMonth(m, y) { return /4|6|9|11/.test(m)?30:m==2?(!(y%4)&&y%100)||!(y%400)?29:28:31; } 

Spécifications :

  1. Il semble qu'il n'y ait pas besoin de réduire le mois. Javascript n'a rien à voir avec cela, car nous ne l'utilisons que pour la comparaison, donc j'ai utilisé les numéros de mois réels pour plus de clarté.

  2. Pourquoi écrire le nombre d'avril, juin, septembre et novembre hors service? C'est tout simplement déroutant.

  3. * En option, nous pouvons augmenter le mois ( ++m ) pour obtenir une version (new Date()).getMonth() en entrée

J'ai rencontré cette question tout en jouant avec un projet de hobby C / C ++ / C #. Donc, bien que cette réponse ne soit pas pertinente pour l'OP, le reste des réponses / commentaires semble concerner JavaScript "golf"; Qui est un peu d'art noir en raison des aléas de JS JIT, mais de l'amusement néanmoins.

Debout sur les épaules de GitaarLAB, TrueBlueAussie, et autres , je propose:

 return m===2?y&3||!(y%25)&&y&15?28:29:30|(m+(m>>3)); 

essaye ça:

 function DaysinMonth(aDate) { return aDate.setMonth(aDate.getMonth()+1, 0).getDate(); } 

Essaye ça:

 function daysInMonth(year, month) { var isLeap = ( (!(year % 4)) && ( (year % 100) || (!(year % 400)) ) ); if (month == 2) return (isLeap) ? 29 : 28; return 30 + (month % 2); }