How do I properly categorize leap years in my if-statements? - python

I'm writing a code that gives the user the day of the week, depending on which ever date (between the year 1583 and 9999) the user puts in. My problem is leap years. Leap years can be mathematically calculated with Zellers congruence: https://en.wikipedia.org/wiki/Zeller%27s_congruence
You can boil down the formula to the following statement:
It is a leap year if the year is evenly divisible by 400, or if it is evenly divisible by 4 but not evenly divisible by 100.
My code does a fine job with this, unless the year is true in both if-statements. For example: 2016. It is a leap year, which makes the first if-statement true. But it´s also NOT evenly divisible by 400. Which makes it true in the second if-statement. So when I run the program I get prompted with "Day: " twice.
Any tips on how to fix this?
The code in question:
if (year % 400 == 0) or ((year % 4 == 0) and (year % 100 != 0)):
day = int(input("Day: "))
while day < 1 or day > 29:
print("Out of allowed range 1 to 29")
day = int(input("Day: "))
continue
if ((year % 4 != 0) and (year % 100 == 0)) or (year % 400 != 0):
day = int(input("Day: "))
while day < 1 or day > 28:
print("Out of allowed range 1 to 28")
day = int(input("Day: "))
continue
I´ve tried changing the 'or' operator to 'and' but that doesn´t really do anything
if ((year % 4 != 0) and (year % 100 == 0)) or (year % 400 != 0):
if ((year % 4 != 0) and (year % 100 == 0)) and (year % 400 != 0):
I've also tried manually putting in the leap years that are similar to 2016. But that doesn't really solve my problem.
The entire code:
x = [1,3,5,7,8,10,12]
y = [4,6,9,11]
year = int(input("Year: "))
while year < 1583 or year > 9999:
print("Out of allowed range 1583 to 9999")
year = int(input("Year: "))
month = int(input("Month: "))
while month < 1 or month >12:
print("Out of allowed range 1 to 12")
month = int(input("Month: "))
if month in x:
day = int(input("Day: "))
while day < 1 or day > 31:
print("Out of allowed range 1 to 31")
day = int(input("Day: "))
elif month in y:
day = int(input("Day: "))
while day < 1 or day > 30:
print("Out of allowed range 1 to 30")
day = int(input("Day: "))
elif month == 2:
if (year % 400 == 0) or ((year % 4 == 0) and (year % 100 != 0)):
day = int(input("Day: "))
while day < 1 or day > 29:
print("Out of allowed range 1 to 29")
day = int(input("Day: "))
continue
if ((year % 4 != 0) and (year % 100 == 0)) or (year % 400 != 0):
day = int(input("Day: "))
while day < 1 or day > 28:
print("Out of allowed range 1 to 28")
day = int(input("Day: "))
continue
if month == 1 or month == 2:
month += 12
year -= 1
weekday = (( day + 13*(month+1)//5 + year + year//4
- year//100 + year//400 ) % 7)
print("It is a", end = ' ')
if weekday == 0:
print("Saturday")
elif weekday == 1:
print("Sunday")
elif weekday == 2:
print("Monday")
elif weekday == 3:
print("Tuesday")
elif weekday == 4:
print("Wednesday")
elif weekday == 5:
print("Thursday")
elif weekday == 6:
print("Friday")

The condition in your first if is correct:
(year % 400 == 0) or ((year % 4 == 0) and (year % 100 != 0))
But from De Morgan's law,
the opposite condition is
(year % 400 != 0) and ((year % 4 != 0) or (year % 100 == 0))
So you want to use that as the condition in your second if for February.
Or to be more clear, you can make a function for determining if it's a leap year:
def is_leap_year(year):
return (year % 400 == 0) or ((year % 4 == 0) and (year % 100 != 0))
And then for February:
if is_leap_year(year):
# Get a day between 1 and 29
else:
# Get a day between 1 and 28

There area bunch of built-in modules in Python that are really useful, one of them is the datetime module which makes calculations with dates much easier. Your solution could be condensed into this code:
import datetime
while True:
try:
year=int(input('Year:'))
month=int(input('Month:'))
day=int(input('Day:'))
date = datetime.datetime(year,month,day)
print(date.strftime('%A'))
break
except ValueError as e:
print(e)
The ValueError will have the reason why it failed to create a datetime from the input parameters. You can still check for additional constraints, like the year and raise a ValueError(<your message>) when it's out of range.

Related

finding leap year by defining function [duplicate]

I am trying to make a simple calculator to determine whether or not a certain year is a leap year.
By definition, a leap year is divisible by four, but not by one hundred, unless it is divisible by four hundred.
Here is my code:
def leapyr(n):
if n%4==0 and n%100!=0:
if n%400==0:
print(n, "is a leap year.")
elif n%4!=0:
print(n, "is not a leap year.")
print(leapyr(1900))
When I try this inside the Python IDLE, the module returns None. I am pretty sure that I should get 1900 is a leap year.
Use calendar.isleap:
import calendar
print(calendar.isleap(1900))
As a one-liner function:
def is_leap_year(year):
"""Determine whether a year is a leap year."""
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
It's similar to the Mark's answer, but short circuits at the first test (note the parenthesis).
Alternatively, you can use the standard library's calendar.isleap, which has exactly the same implementation:
from calendar import isleap
print(isleap(1900)) # False
You test three different things on n:
n % 4
n % 100
n % 400
For 1900:
1900 % 4 == 0
1900 % 100 == 0
1900 % 400 == 300
So 1900 doesn't enter the if clause because 1900 % 100 != 0 is False
But 1900 also doesn't enter the else clause because 1900 % 4 != 0 is also False
This means that execution reaches the end of your function and doesn't see a return statement, so it returns None.
This rewriting of your function should work, and should return False or True as appropriate for the year number you pass into it. (Note that, as in the other answer, you have to return something rather than print it.)
def leapyr(n):
if n % 400 == 0:
return True
if n % 100 == 0:
return False
if n % 4 == 0:
return True
return False
print leapyr(1900)
(Algorithm from Wikipedia)
The whole formula can be contained in a single expression:
def is_leap_year(year):
return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0
print n, " is a leap year" if is_leap_year(n) else " is not a leap year"
Your function doesn't return anything, so that's why when you use it with the print statement you get None. So either just call your function like this:
leapyr(1900)
or modify your function to return a value (by using the return statement), which then would be printed by your print statement.
Note: This does not address any possible problems you have with your leap year computation, but ANSWERS YOUR SPECIFIC QUESTION as to why you are getting None as a result of your function call in conjunction with your print.
Explanation:
Some short examples regarding the above:
def add2(n1, n2):
print 'the result is:', n1 + n2 # prints but uses no *return* statement
def add2_New(n1, n2):
return n1 + n2 # returns the result to caller
Now when I call them:
print add2(10, 5)
this gives:
the result is: 15
None
The first line comes form the print statement inside of add2(). The None from the print statement when I call the function add2() which does not have a return statement, causing the None to be printed. Incidentally, if I had just called the add2() function simply with (note, no print statement):
add2()
I would have just gotten the output of the print statement the result is: 15 without the None (which looks like what you are trying to do).
Compare this with:
print add2_New(10, 5)
which gives:
15
In this case the result is computed in the function add2_New() and no print statement, and returned to the caller who then prints it in turn.
A leap year is exactly divisible by 4 except for century years (years ending with 00). The century year is a leap year only if it is perfectly divisible by 400. For example,
if( (year % 4) == 0):
if ( (year % 100 ) == 0):
if ( (year % 400) == 0):
print("{0} is a leap year".format(year))
else:
print("{0} is not a leap year".format(year))
else:
print("{0} is a leap year".format(year))
else:
print("{0} is not a leap year".format(year))
If you don't want to import calendar and apply .isleap method you can try this:
def isleapyear(year):
if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0):
return True
return False
In the Gregorian calendar, three conditions are used to identify leap years:
The year can be evenly divided by 4, is a leap year, unless:
The year can be evenly divided by 100, it is NOT a leap year, unless:
The year is also evenly divisible by 400. Then it is a leap year.
This means that in the Gregorian calendar, the years 2000 and 2400 are leap years, while 1800, 1900, 2100, 2200, 2300 and 2500 are NOT leap years. source
def is_leap(year):
leap = False
if year % 4 == 0:
leap = True
if year % 4 == 0 and year % 100 == 0:
leap = False
if year % 400 == 0:
leap = True
return leap
year = int(input())
leap = is_leap(year)
if leap:
print(f"{year} is a leap year")
else:
print(f"{year} is not a leap year")
The logic in the "one-liner" works fine. From personal experience, what has helped me is to assign the statements to variables (in their "True" form) and then use logical operators for the result:
A = year % 4 == 0
B = year % 100 == 0
C = year % 400 == 0
I used '==' in the B statement instead of "!=" and applied 'not' logical operator in the calculation:
leap = A and (not B or C)
This comes in handy with a larger set of conditions, and to simplify the boolean operation where applicable before writing a whole bunch of if statements.
An alternative one liner:
((((y % 4) + (int((y - (y % 100)) / y) * ((y % 400) / 100))) - 1) < 0)
This was something that I put together for fun (?) that is also 1:1 compatible with C.
(y % 4) >>>It first checks if the year is a leap year via the typical mod-4 check.
(int((y - (y % 100)) / y) >>>It then accounts for those years divisible by 100. If the year is evenly divisible by 100, this will result in a value of 1, otherwise it will result in a value of 0.
((y % 400) / 100))) >>>Next, the year is divided by 400 (and subsequently 100, to return 1, 2, or 3 if it is not.
These two values
(int(y - (y % 100)) / y)
&
((y % 400) / 100)))
are then multiplied together. If the year is not divisible by 100, this will always equal 0, otherwise if it is divisible by 100, but not by 400, it will result in 1, 2, or 3. If it is divisible by both 100 and 400, it will result in 0.
This value is added to (y % 4), which will only be equal to 0 if the year is a leap year after accounting for the edge-cases.
Finally, 1 is subtracted from this remaining value, resulting in -1 if the year is a leap year, and either 0, 1, or 2 if it is not. This value is compared against 0 with the less-than operator. If the year is a leap year this will result in True (or 1, if used in C), otherwise it will return False (or 0, if used in C).
Please note: this code is horribly inefficient, incredibly unreadable, and a detriment to any code attempting to follow proper practices. This was an exercise of mine to see if I could do so, and nothing more.
Further, be aware that ZeroDivisionErrors are a consequence of the input year equaling 0, and must be accounted for.
For example, a VERY basic timeit comparison of 1000 executions shows that, when compared against an equivalent codeblock utilizing simple if-statements and the modulus operator, this one-liner is roughly 5 times slower than its if-block equivalent.
That being said, I do find it highly entertaining!
The missing part is the use of return statement:
def is_year_leap(year):
if year % 100 == 0:
if year % 400 == 0:
return True
else:
return False
elif year % 4 == 0:
return True
else:
return False
x = is_year_leap(int(input('Enter any year: ')))
print(x)
I tried solving in this way and it as work for me like a charm !!!
Logic I applied to find leap year or not
print([ (1900 % 4 == 0 ) , (1900 % 400 == 0) , (1900 % 100 == 0) ] )
print([ (2022 % 4 == 0 ) , (2022 % 400 == 0) , (2022 % 100 == 0) ] )
print([ (2000 % 4 == 0 ) , (2000 % 400 == 0) , (2000 % 100 == 0) ] )
print([ (1896 % 4 == 0 ) , (1896 % 400 == 0) , (1896 % 100 == 0) ] )
print([ (2020 % 4 == 0 ) , (2020 % 400 == 0) , (2020 % 100 == 0) ] )
Output :
[True, False, True]
[False, False, False]
[True, True, True]
[True, False, False]
[True, False, False]
My code :
yy = 2100
lst = [ (yy % 4 == 0) , (yy % 400 == 0) , (yy % 100 == 0) ]
if lst.count(True) in [0,2]:
print('Not Leap Year')
else:
print('Leap Year')
Output :
Not Leap Year
Incase you find any issue in my code feel free to guide me
From 1700 to 1917, official calendar was the Julian calendar. Since then they we use the Gregorian calendar system. The transition from the Julian to Gregorian calendar system occurred in 1918, when the next day after January 31st was February 14th. This means that 32nd day in 1918, was the February 14th.
In both calendar systems, February is the only month with a variable amount of days, it has 29 days during a leap year, and 28 days during all other years. In the Julian calendar, leap years are divisible by 4 while in the Gregorian calendar, leap years are either of the following:
Divisible by 400.
Divisible by 4 and not divisible by 100.
So the program for leap year will be:
def leap_notleap(year):
yr = ''
if year <= 1917:
if year % 4 == 0:
yr = 'leap'
else:
yr = 'not leap'
elif year >= 1919:
if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0):
yr = 'leap'
else:
yr = 'not leap'
else:
yr = 'none actually, since feb had only 14 days'
return yr

when i run it through a VPL it passes 13/16 tests

year=int(input("Year: "))
while year<1583 or year>9999:
print("Out of allowed range 1583 to 9999")
year=int(input("Year: "))
leap_year=year%4==0 and (year%100 !=0 or year%400==0)
month=[1,12]
month=int(input("Month: "))
while month<1 or month >12:
print ("Out of allowed range 1 to 12")
month=int(input("Month: "))
day=int(input("Day: "))
if month==1 or month==2:
month+=12
year-=1
if month in [1,3,5,7,8,10,12]:
while day<1 or day> 31:
print("Out of allowed range 1 to 31")
day=int(input("Day: "))
if month in [4,6,9,11]:
while day<1 or day >30:
print("Out of allowed range 1 to 30")
day=int(input("Day: "))
if month==2:
if leap_year:
while day<1 or day>29:
print("Out of allowed range 1 to 29")
day=int(input("Day: "))
weekday = ( day + 13*(month+1)// 5 + year + year// 4- year//100+year// 400)% 7
if weekday==0:
print("It is a Saturday.")
elif weekday==1:
print("It is a Sunday.")
elif weekday==2:
print("It is a Monday.")
elif weekday==3:
print("It is a Tuesday.")
elif weekday==4:
print("It is a Wednesday.")
elif weekday==5:
print("It is a Thursday.")
elif weekday==6:
print("It is a Friday.")`
This is the code I wrote and when i run it through a VPL it passes 13/16 tests. The ones it does not pass is :
year: 1900 month:2 day: 29
year: 2018 month:1 day: 32
year: 2018 month:2 day: 32
I've been trying different things but I dont know what is wrong ie. how to correct it. Excuse the low skill level, I've been learning for a week only.
First problem is this code:
if month==1 or month==2:
month+=12
year-=1
If month is 1 or 2 then month becomes 13 or 14, then the next validation tests fail to detect the bad day of the month.
And next problem, this fails to check for condition day < 1 or day > 28 if leap_year = False as in case of 1900, month=2, day=29.
if month==2:
if leap_year:
while day<1 or day>29:
...
Can rewrite like this:
if month==2:
if leap_year:
max_day = 29
else:
max_day = 28
while day < 1 or day > max_day:
print(f"Out of allowed range 1 to {max_day}")
day=int(input("Day: "))

How can I check if a year is a leap year using Python?

I am trying to solve this question with this code:
is_leap_year = False
not_leap_year = True
input_year = int(input())
if (input_year % 4 == 0 or input_year % 400 == 0):
print(input_year, '- leap year')
elif (input_year % 4 != 0 and input_year % 400 != 0):
print(input_year, '- not a leap year')
Why is my code still reading 1900 as a leap year?
Divisibility by 400 is an exception to the rule that years divisible by 100 are not leap years, which itself is an exception to the rule that years divisible by 4 are leap years. If you wrote it out in sequence, you might write
if year % 400 == 0: # Some centuries are leap years...
print("leap year")
elif year % 100 == 0: # ... but most are not ...
print("not leap year")
elif year % 4 == 0: # ... even though other divisibly-by-four years are
print("leap year")
else:
print("not leap year")
or work your way up
if year % 4 != 0:
print("not a leap year")
elif year % 100 != 0:
print("leap year")
elif year % 400 != 0:
print("not a leap year")
else:
print("leap year")
Combining these into a single test would be something like
if year % 4 != 0 or (year % 100 == 0 and year % 400 != 0):
print("not a leap year")
else:
print("leap year")
which I find a little harder to follow than a series of simple tests.
(Given the nature of a solar year, making every year divisible by 400 a leap year is also a problem, though not as big a one as making every century year a leap year. People wanting to avoid drifts over the millenia will propose additional exceptions like "years divisible by 4000, or 40,000, or something, should not be leap years"; no official rule exists yet, though.)
Because 1900 % 4 is actually 0, so the first if conditional is True ( True or False is True) and then it doesn't execute the second if block because is an elif (else if, and since the first was True, there is no need to execute the else part).
Try like this!
year = int(input("Input year: "))
if year % 4 == 0:
print("Year is leap.")
if year % 100 == 0 and year % 400 != 0:
print("Year is common.")
else:
print("Year is common.")
Because the first condition input_year % 4 == 0 evaluates to True.
1900/4= 475 => input_year%4 == 0 is True => for your code 1900 is a leap year
1901/4 = 475,25 => input_year%4 == 0 is false => for your code 1901 is not a leap year
1900 is not a leap year, your calculation is not correct.
here is the code for leap year calculation:
if (year % 4) == 0:
if (year % 100) == 0:
if (year % 400) == 0:
print("{0} is a leap year".format(year))
else:
print("{0} is not a leap year".format(year))
else:
print("{0} is a leap year".format(year))
else:
print("{0} is not a leap year".format(year))
You can write a simplified function taking advantage of Truthy/Falsely
if not(year % 400) or (not(year % 4) and year % 100) : return True
return False```
print(isLeapYear(1900)) # False
print(isLeapYear(1896)) # True
Instead of "or" use "and" in the first if statement.
Both conditions need to be met.

Why are declaring leap value as false after defining function?

I have started learning Python and came across this code:This is leap year program.
Why are we defining leap = False .The output will be true or false.
def is_leap(year):
leap = False
return year % 4 == 0 and (year % 400 == 0 or year % 100 != 0)
year = int(input())
print(is_leap(year))
We don't need to define leap=False since it is not being used in the code, so you can just remove it and do.
def is_leap(year):
return year % 4 == 0 and (year % 400 == 0 or year % 100 != 0)
year = int(input())
print(is_leap(year))
A bad way to write this and use leap will be
def is_leap(year):
leap = year % 4 == 0 and (year % 400 == 0 or year % 100 != 0)
return leap
year = int(input())
print(is_leap(year))
The leap variable in this function isn't even used, and as you assumed, that line is just redundant, and can (should!) be removed.

Python get days in a month output 0

When ever I ran this the output is always 0 where i was expecting like 29 or 30.
import datetime
def days_in_month(year, month):
"""
Inputs:
year - an integer between datetime.MINYEAR and datetime.MAXYEAR
representing the year
month - an integer between 1 and 12 representing the month
Returns:
The number of days in the input month.
"""
#if month is december, we proceed to next year
def month_december(month):
if month == 12:
return 1
else:
return month
#if month is december, we proceed to next year
def year_december(year, month):
if month == 12:
return new_year + 1
else:
return year
#verify if month/year is valid
if (month < 1) or (month > 12):
print ("please enter a valid month")
elif (year < 1) or (year > 9999):
print ("please enter a valid year between 1 - 9999")
else:
#subtract current month from next month then get days
date1 = (datetime.date(year_december(year, month), month_december(month), 1) - datetime.date(year, month, 1)).days
print (date1)
days_in_month(1997, 1)
As daniel told there is a standard library method. It is always better to reuse than reinvent.
import calender
def days_in_month(year, month):
if (month < 1) or (month > 12):
print ("please enter a valid month")
elif (year < 1) or (year > 9999):
print ("please enter a valid year between 1 - 9999")
else:
return calendar.monthrange(year, month)[1]
You forgot to add one month at first parameter.
Your codes:
datetime.date(year_december(year, month), month_december(month), 1)
= datetime.date(year, month, 1)
New codes:
date1 = (datetime.date(year_december(year, month+1), month_december(month+1), 1) - datetime.date(year, month, 1)).days
But pay an attention on the result will be wrong if December, you need to improve it like below:
Full codes:
import datetime
def days_in_month(year, month):
"""
Inputs:
year - an integer between datetime.MINYEAR and datetime.MAXYEAR
representing the year
month - an integer between 1 and 12 representing the month
Returns:
The number of days in the input month.
"""
#if month is december, we proceed to next year
def month_december(month):
if month > 12:
return month-12 #minus 12 if cross year.
else:
return month
#if month is december, we proceed to next year
def year_december(year, month):
if month > 12:
return year + 1
else:
return year
#verify if month/year is valid
if (month < 1) or (month > 12):
print ("please enter a valid month")
elif (year < 1) or (year > 9999):
print ("please enter a valid year between 1 - 9999")
else:
#subtract current month from next month then get days
date1 = (datetime.date(year_december(year, month+1), month_december(month+1), 1) - datetime.date(year, month, 1)).days
print (date1)
days_in_month(1997, 12)
days_in_month(1998, 1)
days_in_month(1998, 2)
Test Case
days_in_month(1997, 12)
days_in_month(1998, 1)
days_in_month(1998, 2)
Output
31
31
28
[Finished in 0.187s]
There is a really cool method I like, and you don't have to import anything. You just need to have two one-line functions. For input you need the year (as integer) and month (as integer) - which both comes from the date it self.
So:
function: check if it's a leap year or not.
function: create a list of the days (corrected with leap year) and call the item of it with the month.
def is_leap_year(year):
return ((year % 4 == 0) and (year % 100 != 0)) or (year % 400 == 0)
def get_days_in_month(year, month):
return [31, (29 if is_leap_year(year) else 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1]
Check it out.

Categories