javascript to find leap year
Asked Answered
N

16

31

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 +'/' +  '';
    }
}
Nighthawk answered 17/11, 2011 at 22:50 Comment(4)
"Stopping" how? Is there an error?Plebs
it never evaluates the year to see if it is a leap year it goes straight to the field.focus and field.value whether it is a leap year or notNighthawk
Your conditions look a little odd - as they're currently written now, you only check day for values of 29 or greater (based on the day == 29 and day > 28 if clauses). I'm assuming that you meant to write day <= 28, but if that's the case, you could drop the second else if clause and use an else clause directly. It might also be safer to add an additional set of parenthesis to your leap year clause: if (year % 4 != 0 || (year % 100 == 0 && year % 400 != 0))Iridotomy
You might need to show some of the surrounding code for how those variables are being set. If you're using a Date object at all remember that it uses zero-based months.Helbonia
W
130

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.

Who answered 17/11, 2011 at 23:35 Comment(5)
Holy cow. What a hack. :)Imprisonment
Use for low volume scenarios only as this is around 100 times slower than using something like isLeap = !((yr % 4) || (!(yr % 100) && (yr % 400))); jsperf.com/ily/7Sublieutenant
what does the == 1 do here?Heavyladen
@RymanHolmes Months in JavaScript's Date object are zero-indexed. On a leap year, the 29th day of the 1st month (February) is valid, so getMonth() returns 1 (February). On a non-leap year, JavaScript "corrects" the 29th of February to the 1st of March, so getMonth() will return 2 (March).Dasheen
This doesn't work on IE11 as passing 29th Feb get's corrected to 28th Feb in the resulting Date() object. Therefore returning 1 and incorrectly flagging as leap year.Tabes
S
21

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
Sublieutenant answered 24/10, 2013 at 16:3 Comment(0)
B
7

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

Blower answered 14/6, 2013 at 20:12 Comment(2)
As this is just combining boolean compares with boolean results, you can express this without the conditional operators but just &&'s, ||'s and short-circuiting. Also around 5% faster: jsperf.com/ily/6Sublieutenant
Do you know what a negation is by now?Karilynn
P
6
isLeap = !(new Date(year, 1, 29).getMonth()-1)

...subtraction by one should work even faster than compare on most CPU architectures.

Patriciate answered 1/4, 2013 at 16:41 Comment(2)
If you were required to calculate 1000s of these per second I might agree, however readability should trump speed when the speed difference concerned is virtually negligible between them.Sublieutenant
Just ran some speed tests and new Date is around 100 times slower than using boolean logic (say something like !((yr % 4) || (!(yr % 100) && (yr % 400)))). You could say I have now thrown readability out the window with this one for the sake of speed, but 100 times may be worth it :)Sublieutenant
S
3

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;
};
Suttee answered 2/10, 2015 at 2:51 Comment(1)
+ for the history lessons. Now the question: were leap years not introduced retroactive?Joung
W
3
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.';
    }
}
Wareroom answered 5/1, 2021 at 5:48 Comment(0)
H
3

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; 
Hereon answered 25/6, 2021 at 12:24 Comment(0)
L
2

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>
Laurencelaurene answered 6/3, 2018 at 5:19 Comment(0)
V
1

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;
Veridical answered 9/8, 2013 at 14:47 Comment(0)
H
1

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
Holms answered 5/7, 2020 at 22:5 Comment(0)
S
1

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
Saucedo answered 15/1, 2023 at 16:14 Comment(0)
O
0

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

Oakes answered 4/2, 2019 at 14:33 Comment(0)
T
0

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
Towelling answered 4/9, 2019 at 18:30 Comment(0)
T
0
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);
Timi answered 19/1, 2021 at 10:6 Comment(1)
While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.Erna
S
0

Alternative non-conditionals solution:

const leapYear = y => (y % 4 === 0) + (y % 100 !== 0) + (y % 400 === 0) === 2
Snaggy answered 8/6, 2022 at 21:19 Comment(0)
R
0

This will return boolean:

function checkLeapYear(year) {
    return(new Date(year, 1, 29).getDate() === 29);
}

This will return number of days:

function countYearDays(year) {
    if (new Date(year, 1, 29).getDate() === 29)
        return 366;
    else
        return 365;
}
Retroversion answered 12/3, 2023 at 20:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.