javascript to find leap year - javascript

How can I get the code below to work when I have a month of february? Currently it is getting to the day and then stopping before getting to the if to determine whether it is a leap year.
if (month == 2) {
if (day == 29) {
if (year % 4 != 0 || year % 100 == 0 && year % 400 != 0) {
field.focus();
field.value = month +'/' + '';
}
}
else if (day > 28) {
field.focus();
field.value = month +'/' + '';
}
}

It's safer to use Date objects for datetime stuff, e.g.
isLeap = new Date(year, 1, 29).getMonth() == 1
Since people keep asking about how exactly this works, it has to do with how JS calculates the date value from year-month-day (details here). Basically, it first calculates the first of the month and then adds N -1 days to it. So when we're asking for the 29th Feb on a non-leap year, the result will be the 1st Feb + 28 days = 1st March:
> new Date(2015, 1, 29)
< Sun Mar 01 2015 00:00:00 GMT+0100 (CET)
On a leap year, the 1st + 28 = 29th Feb:
> new Date(2016, 1, 29)
< Mon Feb 29 2016 00:00:00 GMT+0100 (CET)
In the code above, I set the date to 29th Feb and look if a roll-over took place. If not (the month is still 1, i.e. February), this is a leap year, otherwise a non-leap one.

Compared to using new Date() this is is around 100 times faster!
Update:
This latest version uses a bit test of the bottom 3 bits (is it a multiple of 4), as well as a check for the year being a multiple of 16 (bottom 4 bits in binary is 15) and being a multiple of 25.
ily = function(y) {return !(y & 3 || !(y % 25) && y & 15);};
http://jsperf.com/ily/15
It is slightly faster again than my previous version (below):
ily = function(yr) {return !((yr % 4) || (!(yr % 100) && (yr % 400)));};
http://jsperf.com/ily/7
It is also 5% faster, compared to the already fast conditional operator version by broc.seib
Speed Test results: http://jsperf.com/ily/6
Expected logic test results:
alert(ily(1900)); // false
alert(ily(2000)); // true
alert(ily(2001)); // false
alert(ily(2002)); // false
alert(ily(2003)); // false
alert(ily(2004)); // true
alert(ily(2100)); // false
alert(ily(2400)); // true

isLeap = !(new Date(year, 1, 29).getMonth()-1)
...subtraction by one should work even faster than compare on most CPU architectures.

Correct and Fast:
ily = function(yr) { return (yr%400)?((yr%100)?((yr%4)?false:true):false):true; }
If you are in a loop or counting the nanoseconds, this is two magnitudes faster than running your year through a new Date() object. Compare the performance here: http://jsperf.com/ily

Better historical computation of leap years.
The code below takes into account that leap years were introduced in 45BC with the Julian calendar, and that the majority of the Western world adopted the Gregorian calendar in 1582CE, and that 0CE = 1BC.
isLeap = function(yr) {
if (yr > 1582) return !((yr % 4) || (!(yr % 100) && (yr % 400)));
if (yr >= 0) return !(yr % 4);
if (yr >= -45) return !((yr + 1) % 4);
return false;
};
Britain and its colonies adopted the Gregorian calendar in 1752, so if you are more Anglo centric this version is better (We'll assume Britain adopted the Julian calendar with Roman conquest starting in 43CE).
isLeap = function(yr) {
if (yr > 1752) return !((yr % 4) || (!(yr % 100) && (yr % 400)));
if (yr >= 43) return !(yr % 4);
return false;
};

JavaScript is expected to be getting a new Date/Time API which exposes a new global object - Temporal. This global object provides JS devs with a nicer way to deal with dates/times. It is currently a stage 3 proposal and should hopefully be available for use shortly.
The temporal api exposes a nice property for checking for leap years - inLeapYear. This returns true if a particular date is a leap year, otherwise false. Below we're using with() to convert the date returned by plainDateISO to one with our particular year:
const isLeap = year => Temporal.now.plainDateISO().with({year}).inLeapYear;
console.log(isLeap(2020)); // true
console.log(isLeap(2000)); // true
console.log(isLeap(1944)); // true
console.log(isLeap(2021)); // false
console.log(isLeap(1999)); // false
If you just want to check if your current system date time is a leap year, you can omit the .with():
// true if this year is a leap year, false if it's not a leap year
const isLeap = Temporal.now.plainDateISO().inLeapYear;

I use this because I hate having to keep referring to January as 0 and February as 1.
To me and PHP and readable dates, February=2. I know it doesn't really matter as the number never changes but it just keeps my brain thinking the same across different code.
var year = 2012;
var isLeap = new Date(year,2,1,-1).getDate()==29;

You can easily make this to work calling .isLeapYear() from momentjs:
var notLeapYear = moment('2018-02-29')
console.log(notLeapYear.isLeapYear()); // false
var leapYear = moment('2020-02-29')
console.log(leapYear.isLeapYear()); // true
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.21.0/moment.min.js"></script>

all in one line 😉
const isLeapYear = (year) => (year % 100 === 0 ? year % 400 === 0 : year % 4 === 0);
console.log(isLeapYear(2016)); // true
console.log(isLeapYear(2000)); // true
console.log(isLeapYear(1700)); // false
console.log(isLeapYear(1800)); // false
console.log(isLeapYear(2020)); // true

function isLeap(year) {
if ( (year % 4 === 0 && year % 100 !== 0) || (year % 4 === 0 && year % 100 === 0 && year % 400 === 0) ) {
return 'Leap year.'
} else {
return 'Not leap year.';
}
}

Pseudo code
if year is not divisible by 4 then not leap year
else if year is not divisible by 100 then leap year
else if year is divisible by 400 then leap year
else not leap year
JavaScript
function isLeapYear (year) {
return year % 4 == 0 && ( year % 100 != 0 || year % 400 == 0 )
}
Using the above code insures you do only one check per year if the year is not divisible by 4
Just by adding the brackets you save 2 checks per year that is not divisible by 4

Another alternative is to see if that year has the date of February 29th. If it does have this date, then you know it is a leap year.
ES6
// Months are zero-based integers between 0 and 11, where Febuary = 1
const isLeapYear = year => new Date(year, 1, 29).getDate() === 29;
Tests
> isLeapYear(2016);
< true
> isLeapYear(2019);
< false

function leapYear(year){
if((year%4==0) && (year%100 !==0) || (year%400==0)){
return true;
}
else{
return false;
}
}
var result = leapYear(1700);
console.log(result);

Alternative non-conditionals solution:
const leapYear = y => (y % 4 === 0) + (y % 100 !== 0) + (y % 400 === 0) === 2

Use this:
Date.prototype.isLeap = function() {
return new Date(this.getFullYear(), 1, 29).getMonth() == 1;
};
Date.prototype.isLeap = function() {
return new Date(this.getFullYear(), 1, 29).getMonth() == 1;
};
console.log(new Date("10 Jan 2020").isLeap()); // True
console.log(new Date("10 Jan 2022").isLeap()); // False

Related

How to determine whether a year is a leap year in JavaScript

I'm trying to determine whether a year is a leap year or not. I'm not sure where i'm missing something because this code is meant to determine that.
Thanks for your help.
let Year = (year) => {
this.year = year;
};
Year.prototype.isLeap = () => {
return (
this.year % 400 === 0 ||
(this.year % 4 === 0 && (this.year % 100 === 0))
);
};
let year = new Year(2014);
year.isLeap();
Thanks I've figured it out.
Initially i did it will the kind of If statement you guys are pointing to here!, so I'm now refactoring to av a cleaner code.
My code was having issue on this line
(this.year % 4 === 0 && (this.year % 100 === 0))
the right syntax is
(this.year % 4 === 0 && !(this.year % 100 === 0))
You could just check the feburary 29th of the given year and see if its changes to march 1st.
const date = new Date(this.year, 1, 29);
return date.getMonth() === 1;
If getMonth() returns 1, then its still feburary which means its leap year.
Number.prototype.isLeap = function() {
return !(this % 4 || !(this % 100) && this % 400);
}
let year = 2000;
console.log(year.isLeap()); // prints true
year = 1900;
console.log(year.isLeap()); // prints false
year = 1904;
console.log(year.isLeap()); // prints true
year = 2003;
console.log(year.isLeap()); // prints false
The following code block will work well on Javascript and also on Typescript if you remove the function keyword. To understand the logic behind this implementation have a look at this link How to determine whether a year is a leap year.
function isLeapYear(year) {
let isLeapObj = {};
if ((year % 4 === 0 && year % 100 != 0) || year % 400 === 0) {
isLeapObj['isLeap'] = true;
isLeapObj['days'] = 366;
} else {
isLeapObj['isLeap'] = false;
isLeapObj['days'] = 365;
}
return isLeapObj;
}
x = isLeapYear(2020);
console.log(x);
For Javscript use the following code
In regards to #brenjt's answer above you might want to change the value 29 to 30
const date = new Date(this.year, 1, 30);
if (date.getMonth() === 1) {
console.log("it's not a leap year");
} else {
console.log("it's a leap year");
}

Check if year is leap year in javascript [duplicate]

This question already has answers here:
javascript to find leap year
(15 answers)
Closed 4 years ago.
function leapYear(year){
var result;
year = parseInt(document.getElementById("isYear").value);
if (years/400){
result = true
}
else if(years/100){
result = false
}
else if(years/4){
result= true
}
else{
result= false
}
return result
}
This is what I have so far (the entry is on a from thus stored in "isYear"), I basically followed this here, so using what I already have, how can I check if the entry is a leap year based on these conditions(note I may have done it wrong when implementing the pseudocode, please correct me if I have)
Edit: Note this needs to use an integer not a date function
function leapYear(year)
{
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
The function checks if February has 29 days. If it does, then we have a leap year.
ES5
function isLeap(year) {
return new Date(year, 1, 29).getDate() === 29;
}
ES6
const isLeap = year => new Date(year, 1, 29).getDate() === 29;
Result
isLeap(1004) // true
isLeap(1001) // false
A faster solution is provided by Kevin P. Rice here:https://stackoverflow.com/a/11595914/5535820
So here's the code:
function leapYear(year)
{
return (year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0);
}
If you're doing this in an Node.js app, you can use the leap-year package:
npm install --save leap-year
Then from your app, use the following code to verify whether the provided year or date object is a leap year:
var leapYear = require('leap-year');
leapYear(2014);
//=> false
leapYear(2016);
//=> true
Using a library like this has the advantage that you don't have to deal with the dirty details of getting all of the special cases right, since the library takes care of that.
You can use the following code to check if it's a leap year:
ily = function(yr) {
return (yr % 400) ? ((yr % 100) ? ((yr % 4) ? false : true) : false) : true;
}
You can try using JavaScript's Date Object
new Date(year,month).getFullYear()%4==0
This will return true or false.
My Code Is Very Easy To Understand
var year = 2015;
var LeapYear = year % 4;
if (LeapYear==0) {
alert("This is Leap Year");
} else {
alert("This is not leap year");
}

How to validate a date?

I'm trying to test to make sure a date is valid in the sense that if someone enters 2/30/2011 then it should be wrong.
How can I do this with any date?
One simple way to validate a date string is to convert to a date object and test that, e.g.
// Expect input as d/m/y
function isValidDate(s) {
var bits = s.split('/');
var d = new Date(bits[2], bits[1] - 1, bits[0]);
return d && (d.getMonth() + 1) == bits[1];
}
['0/10/2017','29/2/2016','01/02'].forEach(function(s) {
console.log(s + ' : ' + isValidDate(s))
})
When testing a Date this way, only the month needs to be tested since if the date is out of range, the month will change. Same if the month is out of range. Any year is valid.
You can also test the bits of the date string:
function isValidDate2(s) {
var bits = s.split('/');
var y = bits[2],
m = bits[1],
d = bits[0];
// Assume not leap year by default (note zero index for Jan)
var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
// If evenly divisible by 4 and not evenly divisible by 100,
// or is evenly divisible by 400, then a leap year
if ((!(y % 4) && y % 100) || !(y % 400)) {
daysInMonth[1] = 29;
}
return !(/\D/.test(String(d))) && d > 0 && d <= daysInMonth[--m]
}
['0/10/2017','29/2/2016','01/02'].forEach(function(s) {
console.log(s + ' : ' + isValidDate2(s))
})
Does first function isValidDate(s) proposed by RobG will work for input string '1/2/'?
I think NOT, because the YEAR is not validated ;(
My proposition is to use improved version of this function:
//input in ISO format: yyyy-MM-dd
function DatePicker_IsValidDate(input) {
var bits = input.split('-');
var d = new Date(bits[0], bits[1] - 1, bits[2]);
return d.getFullYear() == bits[0] && (d.getMonth() + 1) == bits[1] && d.getDate() == Number(bits[2]);
}
I recommend to use moment.js. Only providing date to moment will validate it, no need to pass the dateFormat.
var date = moment("2016-10-19");
And then date.isValid() gives desired result.
Se post HERE
This solution does not address obvious date validations such as making sure date parts are integers or that date parts comply with obvious validation checks such as the day being greater than 0 and less than 32. This solution assumes that you already have all three date parts (year, month, day) and that each already passes obvious validations. Given these assumptions this method should work for simply checking if the date exists.
For example February 29, 2009 is not a real date but February 29, 2008 is. When you create a new Date object such as February 29, 2009 look what happens (Remember that months start at zero in JavaScript):
console.log(new Date(2009, 1, 29));
The above line outputs: Sun Mar 01 2009 00:00:00 GMT-0800 (PST)
Notice how the date simply gets rolled to the first day of the next month. Assuming you have the other, obvious validations in place, this information can be used to determine if a date is real with the following function (This function allows for non-zero based months for a more convenient input):
var isActualDate = function (month, day, year) {
var tempDate = new Date(year, --month, day);
return month === tempDate.getMonth();
};
This isn't a complete solution and doesn't take i18n into account but it could be made more robust.
var isDate_ = function(input) {
var status = false;
if (!input || input.length <= 0) {
status = false;
} else {
var result = new Date(input);
if (result == 'Invalid Date') {
status = false;
} else {
status = true;
}
}
return status;
}
this function returns bool value of whether the input given is a valid date or not. ex:
if(isDate_(var_date)) {
// statements if the date is valid
} else {
// statements if not valid
}
I just do a remake of RobG solution
var daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
var isLeap = new Date(theYear,1,29).getDate() == 29;
if (isLeap) {
daysInMonth[1] = 29;
}
return theDay <= daysInMonth[--theMonth]
This is ES6 (with let declaration).
function checkExistingDate(year, month, day){ // year, month and day should be numbers
// months are intended from 1 to 12
let months31 = [1,3,5,7,8,10,12]; // months with 31 days
let months30 = [4,6,9,11]; // months with 30 days
let months28 = [2]; // the only month with 28 days (29 if year isLeap)
let isLeap = ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
let valid = (months31.indexOf(month)!==-1 && day <= 31) || (months30.indexOf(month)!==-1 && day <= 30) || (months28.indexOf(month)!==-1 && day <= 28) || (months28.indexOf(month)!==-1 && day <= 29 && isLeap);
return valid; // it returns true or false
}
In this case I've intended months from 1 to 12. If you prefer or use the 0-11 based model, you can just change the arrays with:
let months31 = [0,2,4,6,7,9,11];
let months30 = [3,5,8,10];
let months28 = [1];
If your date is in form dd/mm/yyyy than you can take off day, month and year function parameters, and do this to retrieve them:
let arrayWithDayMonthYear = myDateInString.split('/');
let year = parseInt(arrayWithDayMonthYear[2]);
let month = parseInt(arrayWithDayMonthYear[1]);
let day = parseInt(arrayWithDayMonthYear[0]);
My function returns true if is a valid date otherwise returns false :D
function isDate (day, month, year){
if(day == 0 ){
return false;
}
switch(month){
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
if(day > 31)
return false;
return true;
case 2:
if (year % 4 == 0)
if(day > 29){
return false;
}
else{
return true;
}
if(day > 28){
return false;
}
return true;
case 4: case 6: case 9: case 11:
if(day > 30){
return false;
}
return true;
default:
return false;
}
}
console.log(isDate(30, 5, 2017));
console.log(isDate(29, 2, 2016));
console.log(isDate(29, 2, 2015));
It's unfortunate that it seems JavaScript has no simple way to validate a date string to these days. This is the simplest way I can think of to parse dates in the format "m/d/yyyy" in modern browsers (that's why it doesn't specify the radix to parseInt, since it should be 10 since ES5):
const dateValidationRegex = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
function isValidDate(strDate) {
if (!dateValidationRegex.test(strDate)) return false;
const [m, d, y] = strDate.split('/').map(n => parseInt(n));
return m === new Date(y, m - 1, d).getMonth() + 1;
}
['10/30/2000abc', '10/30/2000', '1/1/1900', '02/30/2000', '1/1/1/4'].forEach(d => {
console.log(d, isValidDate(d));
});
Hi Please find the answer below.this is done by validating the date newly created
var year=2019;
var month=2;
var date=31;
var d = new Date(year, month - 1, date);
if (d.getFullYear() != year
|| d.getMonth() != (month - 1)
|| d.getDate() != date) {
alert("invalid date");
return false;
}
function isValidDate(year, month, day) {
var d = new Date(year, month - 1, day, 0, 0, 0, 0);
return (!isNaN(d) && (d.getDate() == day && d.getMonth() + 1 == month && d.getYear() == year));
}

Validate number of days in a given month

Performance is of the utmost importance on this one guys... This thing needs to be lightning fast!
How would you validate the number of days in a given month?
My first thought was to make an array containing the days of a given month, with the index representing the month:
var daysInMonth = [
31, // January
28, // February
31, // March
etc.
];
And then do something along the lines of:
function validateDaysInMonth(days, month)
{
if (days < 1 || days > daysInMonth[month]) throw new Error("Frack!");
}
But... What about leap years? How can I implement checking for leap years and keep the function running relatively fast?
Update: I'd like you guys to show me some code which does the days in month- leap year validation.
Here's the flowchart describing the logic used today:
(source: about.com)
function daysInMonth(m, y) { // m is 0 indexed: 0-11
switch (m) {
case 1 :
return (y % 4 == 0 && y % 100) || y % 400 == 0 ? 29 : 28;
case 8 : case 3 : case 5 : case 10 :
return 30;
default :
return 31
}
}
function isValid(d, m, y) {
return m >= 0 && m < 12 && d > 0 && d <= daysInMonth(m, y);
}
I've been doing this using the Date object (assuming it's compiled, and hence blindingly fast compared to scripting).
The trick is that if you enter a too high number for the date part, the Date object wraps over into the next month. So:
var year = 2009;
var month = 1;
var date = 29;
var presumedDate = new Date(year, month, date);
if (presumedDate.getDate() != date)
WScript.Echo("Invalid date");
else
WScript.Echo("Valid date");
This will echo "Invalid date" because presumedDate is actually March 1st.
This leaves all the trouble of leap years etc to the Date object, where I don't have to worry about it.
Neat trick, eh? Dirty, but that's scripting for you...
This will not perform as well as the accepted answer. I threw this in here because I think it is the simplest code. Most people would not need to optimize this function.
function validateDaysInMonth(year, month, day)
{
if (day < 1 || day > 31 || (new Date(year, month, day)).getMonth() != month)
throw new Error("Frack!");
}
It takes advantage of the fact that the javascript Date constructor will perform date arithmetic on dates that are out of range, e.g., if you do:
var year = 2001; //not a leap year!
var month = 1 //February
var day = 29; //not a valid date for this year
new Date(year, month, day);
the object will return Mar 1st, 2001 as the date.
If the month isn't February, get the number from the array. Otherwise, check if the year is leap to return 29, or return 28. Is there a problem with that?
function caldays(m,y)
{
if (m == 01 || m == 03 || m == 05 || m == 07 || m == 08 || m == 10 || m == 12)
{
return 31;
}
else if (m == 04 || m == 06 || m == 09 || m == 11)
{
return 30;
}
else
{
if ((y % 4 == 0) || (y % 400 == 0 && y % 100 != 0))
{
return 29;
}
else
{
return 28;
}
}
}
source: http://www.dotnetspider.com/resources/20979-Javascript-code-get-number-days-perticuler-month-year.aspx
Moment.js
Have you tried moment.js?
The validation is quite easy to use:
var m = moment("2015-11-32");
m.isValid(); // false
I don't know about the performances but hum the project is stared 11,000+ times on GitHub (kind of a quality guarantee).
Source: http://momentjs.com/docs/#/parsing/is-valid/
In computer terms, new Date() and regular expression solutions are slow! If you want a super-fast (and super-cryptic) one-liner, try this one (assuming m is in Jan=1 format):
The only real competition for speed is from #GitaarLab, so I have created a head-to-head JSPerf for us to test on: http://jsperf.com/days-in-month-head-to-head/5
I keep trying different code changes to get the best performance.
Current version
After looking at this related question Leap year check using bitwise operators (amazing speed) and discovering what the 25 & 15 magic number represented, I have come up with this optimized hybrid of answers:
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/
JSPerf results: http://jsperf.com/days-in-month-head-to-head/5
For some reason, (m+(m>>3)&1) is more efficient than (5546>>m&1) on almost all browsers.
It works based on my leap year answer here: javascript to find leap year this answer here Leap year check using bitwise operators (amazing speed) as well as the following binary logic.
A quick lesson in binary months:
If you interpret the index of the desired months (Jan = 1) in binary you will notice that months with 31 days either have bit 3 clear and bit 0 set, or bit 3 set and bit 0 clear.
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
That means you can shift the value 3 places with >> 3, XOR the bits with the original ^ m and see if the result is 1 or 0 in bit position 0 using & 1. Note: It turns out + is slightly faster than XOR (^) and (m >> 3) + m gives the same result in bit 0.
JSPerf results: http://jsperf.com/days-in-month-perf-test/6
I agree with Moayad and TED. Stick with the lookup table unless the month is February. If you need an algorithm for checking leap years, wikipedia has two:
if year modulo 400 is 0 then leap
else if year modulo 100 is 0 then no_leap
else if year modulo 4 is 0 then leap
else no_leap
A more direct algorithm (terms may be grouped either way):
function isLeapYear (year):
if ((year modulo 4 is 0) and (year modulo 100 is not 0)) or (year modulo 400 is 0)
then true
else false
I'm mostly agreeing w/ Moayad. I'd use a table lookup, with an if check on February and the year.
pseudocode:
Last_Day = Last_Day_Of_Month[Month];
Last_Day += (Month == February && Leap_Year(Year)) ? 1 : 0;
Note that Leap_Year() can't be implemented simply as (Year % 4 == 0), because the rules for leap years are way more complex than that. Here's an algorithm cribbed from Wikipedia
bool Leap_Year (int year) {
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
all this logic is already built in to the javascript engine... Why recode it ? Unless you are doing this just as an exercise, you can use the javascript Date object:
Like this:
function daysInMonth(aDate) {
return new Date(aDate.getYear(), aDate.getMonth()+1, 0).getDate();
}
Assuming the JS Date object standard where months are numbered from 0, and you have your daysInMonth array:
var days = daysInMonth[month] + ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0)));
will give you the number of days in the month, with 28 increased to 29 iff the month is February and the year is a leap year.
The days of each month are known easily by exception of February for detail of leap years:
I leave an implementation based on the algorithm that solves this problem:
Algorithm
if (year is not divisible by 4) then (it is a common year)
else if (year is not divisible by 100) then (it is a leap year)
else if (year is not divisible by 400) then (it is a common year)
else (it is a leap year)
More info: https://en.wikipedia.org/wiki/Leap_year#Algorithm
Implementation in Javascript
/**
* Doc: https://en.wikipedia.org/wiki/Leap_year#Algorithm
* param : month is indexed: 1-12
* param: year
**/
function daysInMonth(month, year) {
switch (month) {
case 2 : //Febrary
if (year % 4) {
return 28; //common year
}
if (year % 100) {
return 29; // leap year
}
if (year % 400) {
return 28; //common year
}
return 29; // leap year
case 9 : case 4 : case 6 : case 11 :
return 30;
default :
return 31
}
}
/** Testing daysInMonth Function **/
$('#month').change(function() {
var mVal = parseInt($(this).val());
var yVal = parseInt($('#year').val());
$('#result').text(daysInMonth(mVal, yVal));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>Year</label>
<input type='number' id='year' min='1000' max='2500'>
<label>month</label>
<input type='number' id='month' min='1' max='12'>
<h1>
days: <span id='result' style='color:#E650A0'></span>
</h1>
You can use DateTime to solve this:
new DateTime('20090901')->format('t'); // gives the days of the month
Other solution:
// monthIndex: 0:jan, 11: dic
function daysInMonth (monthIndex, year) {
if (monthIndex ==1) // february case
return (year % 4 == 0 && year % 100) || year % 400 == 0 ? 29 : 28
const monthsWith30days = [3, 5, 8, 10]
return monthsWith30days.includes(monthIndex) ? 30 : 31
}
// testing
const year = new Date().getFullYear()
for (let m=0; m < 12; m += 1) {
console.log(`year ${year} month ${m} has ${daysInMonth(m, year)} days`)
}
OUTPUT
'year 2022 month 0 has 31 days'
'year 2022 month 1 has 28 days'
'year 2022 month 2 has 31 days'
'year 2022 month 3 has 30 days'
'year 2022 month 4 has 31 days'
'year 2022 month 5 has 30 days'
'year 2022 month 6 has 31 days'
'year 2022 month 7 has 31 days'
'year 2022 month 8 has 30 days'
'year 2022 month 9 has 31 days'
'year 2022 month 10 has 30 days'
'year 2022 month 11 has 31 days'

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();
}
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
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.
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();
}
})();
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
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
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.
Here is goes
new Date(2019,2,0).getDate(); //28
new Date(2020,2,0).getDate(); //29
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
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
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
}
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];
}
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!
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;
}
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;
},
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);
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
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)
You can get days in month by this command:
new Date(year, month, 0).getDate();
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.
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);
}
#Tomas Langkaas : I've implemented essentially the same function you've mentioned above in awk, with some minor improvements :
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
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
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

Categories