Home > OS >  How do I properly categorize leap years in my if-statements?
How do I properly categorize leap years in my if-statements?

Time:09-09

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's_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")

CodePudding user response:

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.

CodePudding user response:

The pseudocode for the month February is something like this:

if is_leap_year:
    prompt for day between 1 and 29
if !is_leap_year:
    prompt for day between 1 and 28

Which you could also write as:

if is_leap_year:
    prompt for day between 1 and 29
else:
    prompt for day between 1 and 28

Your first conditional is

(year % 400 == 0) or ((year % 4 == 0) and (year % 100 != 0))

which is consistent with the textual description of leap years that you gave. But your second condition is a little messed up (see De Morgan's Law). So just replace your second if:

if ((year % 4 != 0) and (year % 100 == 0))  or (year % 400 != 0):

with else:

And for clarity you could even define a function for leap years:

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

And use if is_leap_year(year): for checking February's max date.

  • Related