mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-02-17 06:48:09 +00:00
Zeller's Congruence Algorithm (#1095)
* doctest updates * remove unused math import * cleanup (suggestions) * cleanup - Dict fix (TravisCI error)
This commit is contained in:
parent
e313141904
commit
bdbe682568
157
maths/zellers_congruence.py
Normal file
157
maths/zellers_congruence.py
Normal file
|
@ -0,0 +1,157 @@
|
|||
from __future__ import annotations
|
||||
import datetime
|
||||
import argparse
|
||||
|
||||
|
||||
def zeller(date_input: str) -> str:
|
||||
|
||||
"""
|
||||
Zellers Congruence Algorithm
|
||||
Find the day of the week for nearly any Gregorian or Julian calendar date
|
||||
|
||||
>>> zeller('01-31-2010')
|
||||
'Your date 01-31-2010, is a Sunday!'
|
||||
|
||||
Validate out of range month
|
||||
>>> zeller('13-31-2010')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Month must be between 1 - 12
|
||||
>>> zeller('.2-31-2010')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: invalid literal for int() with base 10: '.2'
|
||||
|
||||
Validate out of range date:
|
||||
>>> zeller('01-33-2010')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Date must be between 1 - 31
|
||||
>>> zeller('01-.4-2010')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: invalid literal for int() with base 10: '.4'
|
||||
|
||||
Validate second seperator:
|
||||
>>> zeller('01-31*2010')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Date seperator must be '-' or '/'
|
||||
|
||||
Validate first seperator:
|
||||
>>> zeller('01^31-2010')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Date seperator must be '-' or '/'
|
||||
|
||||
Validate out of range year:
|
||||
>>> zeller('01-31-8999')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Year out of range. There has to be some sort of limit...right?
|
||||
|
||||
Test null input:
|
||||
>>> zeller()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: zeller() missing 1 required positional argument: 'date_input'
|
||||
|
||||
Test length fo date_input:
|
||||
>>> zeller('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Must be 10 characters long
|
||||
>>> zeller('01-31-19082939')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Must be 10 characters long
|
||||
"""
|
||||
|
||||
# Days of the week for response
|
||||
days = {
|
||||
'0': 'Sunday',
|
||||
'1': 'Monday',
|
||||
'2': 'Tuesday',
|
||||
'3': 'Wednesday',
|
||||
'4': 'Thursday',
|
||||
'5': 'Friday',
|
||||
'6': 'Saturday'
|
||||
}
|
||||
|
||||
convert_datetime_days = {
|
||||
0:1,
|
||||
1:2,
|
||||
2:3,
|
||||
3:4,
|
||||
4:5,
|
||||
5:6,
|
||||
6:0
|
||||
}
|
||||
|
||||
# Validate
|
||||
if not 0 < len(date_input) < 11:
|
||||
raise ValueError("Must be 10 characters long")
|
||||
|
||||
# Get month
|
||||
m: int = int(date_input[0] + date_input[1])
|
||||
# Validate
|
||||
if not 0 < m < 13:
|
||||
raise ValueError("Month must be between 1 - 12")
|
||||
|
||||
sep_1:str = date_input[2]
|
||||
# Validate
|
||||
if sep_1 not in ["-","/"]:
|
||||
raise ValueError("Date seperator must be '-' or '/'")
|
||||
|
||||
# Get day
|
||||
d: int = int(date_input[3] + date_input[4])
|
||||
# Validate
|
||||
if not 0 < d < 32:
|
||||
raise ValueError("Date must be between 1 - 31")
|
||||
|
||||
# Get second seperator
|
||||
sep_2: str = date_input[5]
|
||||
# Validate
|
||||
if sep_2 not in ["-","/"]:
|
||||
raise ValueError("Date seperator must be '-' or '/'")
|
||||
|
||||
# Get year
|
||||
y: int = int(date_input[6] + date_input[7] + date_input[8] + date_input[9])
|
||||
# Arbitrary year range
|
||||
if not 45 < y < 8500:
|
||||
raise ValueError("Year out of range. There has to be some sort of limit...right?")
|
||||
|
||||
# Get datetime obj for validation
|
||||
dt_ck = datetime.date(int(y), int(m), int(d))
|
||||
|
||||
# Start math
|
||||
if m <= 2:
|
||||
y = y - 1
|
||||
m = m + 12
|
||||
# maths var
|
||||
c: int = int(str(y)[:2])
|
||||
k: int = int(str(y)[2:])
|
||||
t: int = int(2.6*m - 5.39)
|
||||
u: int = int(c / 4)
|
||||
v: int = int(k / 4)
|
||||
x: int = int(d + k)
|
||||
z: int = int(t + u + v + x)
|
||||
w: int = int(z - (2 * c))
|
||||
f: int = round(w%7)
|
||||
# End math
|
||||
|
||||
# Validate math
|
||||
if f != convert_datetime_days[dt_ck.weekday()]:
|
||||
raise AssertionError("The date was evaluated incorrectly. Contact developer.")
|
||||
|
||||
# Response
|
||||
response: str = f"Your date {date_input}, is a {days[str(f)]}!"
|
||||
return response
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
parser = argparse.ArgumentParser(description='Find out what day of the week nearly any date is or was. Enter date as a string in the mm-dd-yyyy or mm/dd/yyyy format')
|
||||
parser.add_argument('date_input', type=str, help='Date as a string (mm-dd-yyyy or mm/dd/yyyy)')
|
||||
args = parser.parse_args()
|
||||
zeller(args.date_input)
|
Loading…
Reference in New Issue
Block a user