¿Cuál es la mejor manera de determinar la cantidad de días en un mes con JavaScript?

107

He estado usando esta función, pero me gustaría saber cuál es la forma más eficiente y precisa de obtenerla.

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

Respuestas:

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.

El día 0 es el último día del mes anterior. Debido a que el constructor del mes está basado en 0, esto funciona muy bien. Es un truco, pero eso es básicamente lo que estás haciendo al restar 32.

FlySwat
fuente
42
esta sintaxis me ha estado confundiendo por un tiempo. Para seguir el patrón JS, recomendaré implementar el truco como este:return new Date(year, month + 1, 0).getDate();
fguillen
2
Desafortunadamente, esto falla para fechas anteriores al año 1000 d.C., donde solo puede configurar el año correctamente usando SetFullYear (). Para hacerlo a prueba de balas, use la nueva fecha (2000+ (año% 2000), mes, 0) .getDate ()
Noel Walters
4
Nota para mi yo futuro: la ecuación de fguillen con el '+ 1' da 28 días cuando el año es 2014 y el mes es 1 (que, en JavaScript Date-object, significa febrero). Probablemente quiera ir con eso por el menor asombro. ¡Pero qué gran idea de FlySwat!
Harry Pehkonen
@ NoelWalters: tiene razón en que algunos navegadores convierten incorrectamente años de dos dígitos en fechas del siglo XX (por lo tanto, fechas anteriores al 100 d. C., no al 1000 d. C.), sin embargo, su solución no corrige eso en esos navegadores. La única manera de establecer de forma fiable años de dos dígitos es utilizar setFullYear : var d=new Date();d.setFullYear(year, month, date);.
RobG
1
¿Y si monthes 12 ? ¿No debería el Dateconstructor tomar un valor de 0 a 11 ?
anddero
8

Si llama a esta función con frecuencia, puede ser útil almacenar en caché el valor para un mejor rendimiento.

Aquí está la versión de almacenamiento en caché de la respuesta 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
fuente
6
¿Es la rutina interna de C / C ++ tan lenta que requiere almacenamiento en caché?
Pete Alvin
1
@PeteAlvin Depende de la implementación de Date(por lo que no hay una respuesta universal a esa pregunta) y de la frecuencia con la que su código llamará dayInMonthcon los mismos valores. Entonces, la única respuesta sensata es: ¡perfile tu código y compáralo!
dolmen
1
¡Me gusta! Pero en lugar de usar un objeto nuevo cache, utilizo localStorage.
andrew
5

Algunas respuestas (también en otras preguntas) tenían problemas de años bisiestos o usaban el objeto Date. Aunque javascript Date objectcubre aproximadamente 285616 años (100,000,000 de días) a ambos lados del 1 de enero de 1970, estaba harto de todo tipo de inconsistencias de fechas inesperadas en diferentes navegadores (más notablemente del año 0 al 99). También tenía curiosidad por saber cómo calcularlo.

Así que escribí un algoritmo simple y, sobre todo, pequeño para calcular el número correcto de días ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (cláusula 4.3.2.1), por lo que el año0 existe y es un año bisiesto y se admiten años negativos ) un mes y un año determinados.
Utiliza el algoritmo de cortocircuito bitmask-modulo leapYear (ligeramente modificado para js) y el algoritmo común mod-8 month.

Tenga en cuenta que en la AD/BCnotación, el año 0 AD / BC no existe: ¡en cambio, el año 1 BCes el año bisiesto!
SI necesita tener en cuenta la notación BC, simplemente reste un año del valor anual (de lo contrario positivo) primero. (O reste el año 1para obtener más cálculos de años).

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>

¡Tenga en cuenta que los meses deben basarse en 1!

Tenga en cuenta que este es un algoritmo diferente a la búsqueda de números mágicos que usé en mi Javascript para calcular la respuesta del día del año (1 - 366) , porque aquí la rama adicional para el año bisiesto solo se necesita para febrero.

GitaarLAB
fuente
4

Para eliminar la confusión, probablemente haría que la cadena del mes se base, ya que actualmente se basa en 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
Jaybeecave
fuente
4

Con moment.js puedes usar el método 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
fuente
2

Aquí va

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

Sintaxis de ES6

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

devoluciones

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

console.log( d(2020, 6) );
// 30
RASG
fuente
1
Al agregar una nueva respuesta a una pregunta anterior con 14 respuestas existentes, es realmente importante tener en cuenta qué aspecto nuevo de la pregunta aborda su respuesta. ¿Es solo la sintaxis de ES6?
Jason Aller
Entendido. agregará contexto a la respuesta a partir de ahora.
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
        }
Tony Li
fuente
1

Considerando los años bisiestos:

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
fuente
Agradable. Fácil de mirar. Prop [ertie] s para el uso de un mapa en línea / valor de clave inmediata.
Cody
1

Cálculo directo de una sola línea (sin objeto 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

Variación con meses basados ​​en 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
fuente
1

Si desea conocer el número de días del mes actual de un objeto Date, considere el siguiente método:

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

Entonces puedes ejecutarlo así:

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!
mrplantas
fuente
1

En una sola línea:

// 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
fuente
1

Puede ser un poco exagerado en comparación con la respuesta seleccionada :) Pero aquí está:

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

Encontré el código anterior aquí: 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));

Encontré el código anterior aquí: https://github.com/datejs/Datejs/blob/master/src/core.js

Syed
fuente
1

Si va a pasar una variable de fecha, esto puede ser útil

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

daysInThisMonth = getDaysInMonth(new Date());

console.log(daysInThisMonth);

sanka sanjeeva
fuente
-1

Quizás no sea la solución más elegante, pero fácil de entender y mantener; y está probado en batalla.

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
fuente