Chatu
Chatu

Reputation: 4788

What is the best way to determine the number of days in a month with JavaScript?

I've been using this function but I'd like to know what's the most efficient and accurate way to get it.

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

Upvotes: 138

Views: 41022

Answers (21)

RARE Kpop Manifesto
RARE Kpop Manifesto

Reputation: 2915

@Tomas Langkaas : I've implemented essentially the same function you've mentioned above in awk, with some minor improvements :

  1. using conventional arithmetic instead of bit-wise AND ( & ), plus not using implementation-dependent features, making it fully POSIX-awk-complaint and portable (tested and confirmed working on mawk, gawk, and nawk)

2. user can now directly input actual month numbers of 1 - 12 instead of having to remember to pre-adjust them to 0 - 11

  1. instead of relying on hard-coded numerics, every constant, offset, modulo base etc now dynamically generated on the fly by the function itself ,

    while simultaneously being extremely temp variables efficient by recycling both the input month and year variables the moment their original values are no longer required, thus

  2. when February is being called without a year-value, it defaults to NOT-being a leap year, regardless of what the present year is

    {m,g,n}awk '
    
    function _____(_,__) {
        #
        #  _| Month  mm: [1-12]
        # __|  Year yyyy:
        #   |--->  #-days:
        #          in yyyy:mm: combo
        return -(\
        _^(_<_) != --_ \
            ? (_ %((_+=_+=_^=_<_) +--_)) %--_\
            : (_+=_^=_<_) + (__ == "" ||
              __ % (_+=_)         ||
          __% (_*(_*=_++)+_) == ! (__ % (_*_))\
              ) )  \
            -(_^=_<_) -+- ++_^_^_*_ 
    }'
    
    
                    2 1600   29
           2 1700 28
           2 1800 28
     2 1868   29
           2 1900 28
     2 1912   29
     2 1956   29
                    2 2000   29
     2 2012   29
     2 2016   29
     2 2018 28
     2 2020   29
     2 2022 28
     2 2024   29
    

Upvotes: 0

Mykyta Halchenko
Mykyta Halchenko

Reputation: 798

Try this - it returns dictionary with month: days mapping, I think it will be very useful in most cases when people enter this topic:

const getMonthsDaysForYear = (year) => {
  let monthDaysDictionary = {};

  for(let i = 1; i <= 11; i++) {
      const date = new Date(year, i + 1, 0);
      const monthName = date.toLocaleString('en-GB', { month: 'long' });
      monthDaysDictionary[monthName] = date.getDate();
  }

  return monthDaysDictionary;
}
getMonthsDaysForYear(2022);

Note: that month should be started with 1 as it is mentioned in this answer.

Upvotes: 1

Tomas Langkaas
Tomas Langkaas

Reputation: 4731

One-liner direct computation (no Date object):

//m is 0-based, Jan = 0, Dec = 11

function daysInMonth(m,y){
   return 31-(m-1?m%7&1:y&(y%25?3:15)?3:2);
}

console.log(daysInMonth(1, 2003), "days in February in the non-leap year 2003");
console.log(daysInMonth(1, 2004), "days in February in the leap year 2004");
console.log(daysInMonth(1, 2100), "days in February in the non-leap year 2100");
console.log(daysInMonth(1, 2000), "days in February in the leap year 2000");

console.log(daysInMonth(0, 2022), "days in January 2022");
console.log(daysInMonth(1, 2022), "days in February 2022");
console.log(daysInMonth(2, 2022), "days in March 2022");
console.log(daysInMonth(3, 2022), "days in April 2022");
console.log(daysInMonth(4, 2022), "days in May 2022");
console.log(daysInMonth(5, 2022), "days in June 2022");
console.log(daysInMonth(6, 2022), "days in July 2022");
console.log(daysInMonth(7, 2022), "days in August 2022");
console.log(daysInMonth(8, 2022), "days in September 2022");
console.log(daysInMonth(9, 2022), "days in October 2022");
console.log(daysInMonth(10, 2022), "days in November 2022");
console.log(daysInMonth(11, 2022), "days in December 2022");

Explanation

The main idea is to assume that months have 31 days, but subtract 1 if the month is April, June, September, or November; subtract 2 if the month is February in a leap year; or subtract 3 if the month is February in a non-leap year.

In the ternary expression (m - 1 ? /* Not February */ : /* February */), the expression m - 1 checks whether the month is February.

For other months than February, the expression m % 7 makes m even for months with 31 days, and odd for the rest. Subtracting the lowest bit (& 1) results in 31 − 1 days for April, June, September, and November, and 31 − 0 days for the rest.

For February, the expression y & (y % 25 ? 3 : 15) is falsy for leap years, resulting in 31 − 2 days in February. Otherwise, February is 31 − 3 days.

Upvotes: 5

user3693428
user3693428

Reputation: 1

See my function and a test of it:

function numberOfDays(year, month) { // Reference: // https://arslankuyumculuk.com/how-to-calculate-leap-year-formula/ (2022-05-20 16:45 UTC)

numDays=0;
switch(month)
{
    case 1:
        numDays=31;
        break;
    case 2:
        numDays=28;
        break;
    case 3:
        numDays=31;
        break;
    case 4:
        numDays=30;
        break;
    case 5:
        numDays=31;
        break;
    case 6:
        numDays=30;
        break;
    case 7:
        numDays=31;
        break;
    case 8:
        numDays=31;
        break;
    case 9:
        numDays=30;
        break;
    case 10:
        numDays=31;
        break;
    case 11:
        numDays=30;
        break;
    case 12:
        numDays=31;
        break;
}

if(month==2)
{
    if( (year % 100) == 0 )
    {
        if( (year % 400) == 0 )
        {
            numDays=29;
        }
    }
    else
    {
        if( (year % 4) == 0 )
        {
            numDays=29;
        }
    }
}

//
return numDays;

}

// Test:

const years = [2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2100,2400];
month=2;
for (let i = 0; i < years.length; i++) 
{
    let text = "";
    text += years[i] + '/' + month.toString() + ": " + numberOfDays(years[i], month).toString();
    alert(text);
} 

for (let m = 1; m <= 12; m++) 
{
    let text2 = "";
    text2 += "2022/" + m.toString() + ": " + numberOfDays(2022, m).toString();
    alert(text2);
} 

Upvotes: 0

Mehran
Mehran

Reputation: 41

You can get days in month by this command:

new Date(year, month, 0).getDate();

Upvotes: 2

crg
crg

Reputation: 4577

To get the number of days in the current month

var nbOfDaysInCurrentMonth = new Date(Date.UTC(new Date().getUTCFullYear(), new Date().getUTCMonth(), 0)).getDate()

console.log(nbOfDaysInCurrentMonth)

Upvotes: 1

Jaybeecave
Jaybeecave

Reputation: 886

To take away confusion I would probably make the month string based as it is currently 0 based.

function daysInMonth(month,year) {
    var 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

Upvotes: 5

FlySwat
FlySwat

Reputation: 175733

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.

Day 0 is the last day in the previous month. Because the month constructor is 0-based, this works nicely. A bit of a hack, but that's basically what you're doing by subtracting 32.

See more : Number of days in the current month

Upvotes: 247

G Herbowicz
G Herbowicz

Reputation: 1238

One-liner, without using Date objects:

const countDays = (month, year) => 30 + (month === 2 ? (year % 4 === 0 && 1) - 2 : (month + Number(month > 7)) % 2);

returns:

countDays(11,2020) // 30
countDays(2,2020) // 29
countDays(2,2021) // 28

Upvotes: 1

yodog
yodog

Reputation: 6242

ES6 syntax

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

returns

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

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

Upvotes: 3

Sanka Sanjeeva
Sanka Sanjeeva

Reputation: 3560

If you are going to pass a date variable this may helpful

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

daysInThisMonth = getDaysInMonth(new Date());

console.log(daysInThisMonth);

Upvotes: 2

Syed
Syed

Reputation: 16543

May be bit over kill when compared to selected answer :) But here it is:

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

I found the above code over here: 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));

I found the above code over here: https://github.com/datejs/Datejs/blob/master/src/core.js

Upvotes: 2

Masum Billah
Masum Billah

Reputation: 2409

Here is goes

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

Upvotes: 3

kmiklas
kmiklas

Reputation: 13453

Perhaps not the most elegant solution, but easy to understand and maintain; and, it's battle-tested.

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;
},

Upvotes: 1

Shl
Shl

Reputation: 3688

In a single line:

// 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;
}

Upvotes: 1

mrplants
mrplants

Reputation: 677

If you want the number of days in the current month of a Date object, consider the following method:

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

Then you can run it like this:

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!

Upvotes: 1

GitaarLAB
GitaarLAB

Reputation: 14655

Some answers (also on other questions) had leap-year problems or used the Date-object. Although javascript's Date object covers approximately 285616 years (100,000,000 days) on either side of January 1 1970, I was fed up with all kinds of unexpected date inconsistencies across different browsers (most notably year 0 to 99). I was also curious how to calculate it.

So I wrote a simple and above all, small algorithm to calculate the correct (Proleptic Gregorian / Astronomical / ISO 8601:2004 (clause 4.3.2.1), so year 0 exists and is a leap year and negative years are supported) number of day's for a given month and year.
It uses the short-circuit bitmask-modulo leapYear algorithm (slightly modified for js) and common mod-8 month algorithm.

Note that in AD/BC notation, year 0 AD/BC does not exist: instead year 1 BC is the leap-year!
IF you need to account for BC notation then simply subtract one year of the (otherwise positive) year-value first!! (Or subtract the year from 1 for further year-calculations.)

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>

Note, months must be 1-based!

Note, this is a different algorithm then the magic number lookup I used in my Javascript calculate the day of the year (1 - 366) answer, because here the extra branch for the leap-year is only needed for February.

Upvotes: 13

artem_p
artem_p

Reputation: 316

With moment.js you can use daysInMonth() method:

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

Upvotes: 4

Yash
Yash

Reputation: 2183

Considering leap years:

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];
}

Upvotes: 1

Tony Li
Tony Li

Reputation: 116

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
        }

Upvotes: 1

dolmen
dolmen

Reputation: 8706

If you call this function often, it may be useful to cache the value for better performance.

Here is caching version of FlySwat's answer:

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

Upvotes: 7

Related Questions