How to Determine Whether a Year Is a Leap Year

Calculating if a year is a leap year

Solution A

The wording in the specifications is doing this thing where it says check this condition to know if it's a leap year. And then it says I can change my mind if... But then once again I can change my mind if...

We can do the same thing in our code. We can save if it is a leap year, change our mind if it is divisible by 100, and then change our mind again if it is divisible by 400.

def is_leap(year):
leap = False

# The year can be evenly divided by 4, is a leap year
if year%4 == 0:
leap = True

# Unless the year can be evenly divided by 100
if year%4 == 0 and year%100 == 0:
leap = False

# Unless the year is also evenly divisible by 400
if year%4 == 0 and year%100 == 0 and year%400 == 0:
leap True

return leap

Solution B

When you see this type of pattern in your code -- where each condition has the previous condition within it, you might wonder if there is a way it can be refactored, and there is. We can remove the extra repetition in two different ways. We can do as @alexpdev did with nested if statements, or we can combine everything into one ginormous if statement which would look something like this:

def is_leap(year):
if (
# The year can be evenly divided by 4, is a leap year
<logic would go here>

# Unless the year can be evenly divided by 100
and not <logic would go here>

# Unless the year is also evenly divisible by 400
and not <logic would go here>
):
return True
return False

Here is a discussion on which method is better. Some people don't like combining everything into a single if statement when there are a lot of conditions involved, but I don't mind doing so as long as it's tactfully done (like the way Deestan mentions in this question, often accompanied with comments explaining complex logic). I will get back to using this method later, but first I want to see if we can put everything together like so

Solution C

    # doesn't work
if year%4 == 0:
leap = True
elif year%4 == 0 and year%100 == 0:
leap = False
elif year%4 == 0 and year%100 == 0 and year%400 == 0:
leap True

I feel like we should be able to use an if/elif chain, and it's what you were trying to do too, but we end up in trouble because we would only move on to the next elif if year%4 == 0 was false. That's never going to work, so... maybe we can do the inverse. The specification isn't that straightforward, so let's start invert it and see if we can reword it into something a little bit more procedural:

The year is a leap year unless:

  1. It is not divisible by 4
  2. It is divisible by 100 and not 400

Yes, I think this will work nicely. That's pretty straightforward to code up:

def is_leap(year):
# It is not divisible by 4
if year%4 != 0:
return False

# It is divisible by 100 and not 400
elif year%100 == 0 and year%400 != 0:
return False

return True

Solution B

Cool. So that is one option for how we could code this up. Now let's finish that ginormous if statement. It seems like it could get gnarly, but this will actually produce a solution that is very elegant.

Let's start with the first condition

The year can be evenly divided by 4, is a leap year

def is_leap(year):
return year%4 == 0

Then we combine that with

Unless the year can be evenly divided by 100

def is_leap(year):
return year%4 == 0 and not (year%100 == 0)

As we continue on we will have to be watchful about how we combine. We are going to end up with three conditions combined together, but the third one modifies the second one only, so we will need to make sure we use parenthesis correctly here.

Unless the year is also evenly divisible by 400

def is_leap(year):
return year%4 == 0 and not (year%100 == 0 and not (year%400 == 0))

And that will calculate if we have a leap year. If we like, we can use the fact that we x != y is the same thing as not(x==y), and we can use De Morgan's Law to convert that function into

def is_leap(year):
return year%4 == 0 and (year%100 != 0 or year%400 == 0)

Final Solution A

This isn't normally possible, but in this specific question we can use the fact that 400 is a multiple of 100 which is a multiple of 4 to simplify solution A like so:

def is_leap(year):
leap = False

# If we can divide they year by 4, it's probably a leap year
if year%4 == 0:
leap = True

# But every 100 years we skip a leap year
if year%100 == 0:
# when true it also means the year is divisible by 100
# so we can skip checking those conditions
leap = False

# Unless the year is also divisible by 400
if year%400 == 0:
# when true it also means the year is divisible by 100 and by 4
# so we can skip checking those conditions
leap True

return leap

However, we should add some comments to explain the optimization that we've done. Especially because we don't want bugs to be introduced in the future if a new condition needs to be added that can't be optimized in the same way. And with those comments the solution has become a little lengthy.

Final Solution B

Adding some comments

def is_leap(year):
return (
# First check if we have a normal leap year
year%4 == 0
# However, anything divisible by 100 is not considered a leap year
# Unless the year is also a multiple of 400
and (year%100 != 0 or year%400 == 0)
)

This is a pretty elegant solution and also the fastest to execute.

Final Solution C

It just seems a little unnatural to me to be checking for False conditions and returning True as the default. Usually it's the other way around. We can add a second function called is_not_leap

def is_not_leap(year):
# It is not divisible by 4
if year%4 != 0:
return True

# It is divisible by 100 and not 400
elif year%100 == 0 and year%400 != 0:
return True

return False

def is_leap(year):
return not is_not_leap(year)

But now we have when we do year%4 != 0 it's kind of like a double negative. We're checking if it is not divisible by four to know if it is not a leap year. That's still confusing. This solution just seems unnatural to me.

The Winner

Of all three solutions, Solution B is my favorite. It doesn't have any double negatives, doesn't have hidden optimizations, it just works, and it's not that difficult to follow the logic.

How to determine whether a year is a leap year?

Use calendar.isleap:

import calendar
print(calendar.isleap(1900))

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

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.

How to determine weather a year is a leap year, and the years thereafter in Python?

Try changing your code to:

print ("""Enter a year to see if it is a leap year,
then enter the number of years there after you want to check""")

year_start = int(input("\nWhat year do you want to start with?\n"))
num_of_years = int(input("How many years do you want to check?\n"))

# I can't figure out the 'for loop' syntax to loop this statement
for i in range(year_start, year_start + num_of_years):
if (i % 4) == 0:
print (f"{i} is a leap year")
else:
print (f"{i} isn't a leap year")

Example output:

Enter a year to see if it is a leap year,
then enter the number of years there after you want to check

What year do you want to start with?
1994
How many years do you want to check?
8
1994 isn't a leap year
1995 isn't a leap year
1996 is a leap year
1997 isn't a leap year
1998 isn't a leap year
1999 isn't a leap year
2000 is a leap year
2001 isn't a leap year

You can use a for loop and use range for the sequence to iterate. Then you only need (i % 4) == 0, and you don't need the other conditions.

Python how to check if it is a leap year with ==int

Your issue is that int is a type. If you try to compare a number to a type of object, which is what you are doing when you write if year/400 == int :, it will always return False, because these can never be the same.

A better way to check if year/400 is an integer would be:

if year%400 == 0:
return False

This is saying:
If the remainder of year/400 is equal to 0, return False, which is what you wanted.

Some other things are:

You should use elif instead of if in most cases. In this one, it doesn't matter, since the return statement terminates the execution of the function early, but you should still use it anyways. Otherwise, even when you have your final result, it will go through the rest of the if statements.

The other thing isn't related to your code, but your leap year criteria are incorrect. If the year is divisible by 4, then it's a leap year.
Unless the year is divisible by 100, then it's not.
Unless it's divisible by 400, then it is.

Improved code:

def leapyear(year):
if year%400 == 0:
return True
elif year%100 == 0:
return False
elif year%4 == 0:
return True
return False

Calculating leap years

from calendar import isleap
year=input('Year: ')
if isleap(int(year)):
print(29)
else:
print(28)

Or without import:

year=input('Year: ')
if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0):
print(29)
else:
print(28)

Check if year is leap year in javascript

function leapYear(year)
{
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}


Related Topics



Leave a reply



Submit