Skip to content

Commit 66ba297

Browse files
mrvnmchmstokhos
authored andcommitted
Zeller's Congruence Algorithm (TheAlgorithms#1095)
* doctest updates * remove unused math import * cleanup (suggestions) * cleanup - Dict fix (TravisCI error)
1 parent abc61bd commit 66ba297

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed

Diff for: maths/zellers_congruence.py

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
from __future__ import annotations
2+
import datetime
3+
import argparse
4+
5+
6+
def zeller(date_input: str) -> str:
7+
8+
"""
9+
Zellers Congruence Algorithm
10+
Find the day of the week for nearly any Gregorian or Julian calendar date
11+
12+
>>> zeller('01-31-2010')
13+
'Your date 01-31-2010, is a Sunday!'
14+
15+
Validate out of range month
16+
>>> zeller('13-31-2010')
17+
Traceback (most recent call last):
18+
...
19+
ValueError: Month must be between 1 - 12
20+
>>> zeller('.2-31-2010')
21+
Traceback (most recent call last):
22+
...
23+
ValueError: invalid literal for int() with base 10: '.2'
24+
25+
Validate out of range date:
26+
>>> zeller('01-33-2010')
27+
Traceback (most recent call last):
28+
...
29+
ValueError: Date must be between 1 - 31
30+
>>> zeller('01-.4-2010')
31+
Traceback (most recent call last):
32+
...
33+
ValueError: invalid literal for int() with base 10: '.4'
34+
35+
Validate second seperator:
36+
>>> zeller('01-31*2010')
37+
Traceback (most recent call last):
38+
...
39+
ValueError: Date seperator must be '-' or '/'
40+
41+
Validate first seperator:
42+
>>> zeller('01^31-2010')
43+
Traceback (most recent call last):
44+
...
45+
ValueError: Date seperator must be '-' or '/'
46+
47+
Validate out of range year:
48+
>>> zeller('01-31-8999')
49+
Traceback (most recent call last):
50+
...
51+
ValueError: Year out of range. There has to be some sort of limit...right?
52+
53+
Test null input:
54+
>>> zeller()
55+
Traceback (most recent call last):
56+
...
57+
TypeError: zeller() missing 1 required positional argument: 'date_input'
58+
59+
Test length fo date_input:
60+
>>> zeller('')
61+
Traceback (most recent call last):
62+
...
63+
ValueError: Must be 10 characters long
64+
>>> zeller('01-31-19082939')
65+
Traceback (most recent call last):
66+
...
67+
ValueError: Must be 10 characters long
68+
"""
69+
70+
# Days of the week for response
71+
days = {
72+
'0': 'Sunday',
73+
'1': 'Monday',
74+
'2': 'Tuesday',
75+
'3': 'Wednesday',
76+
'4': 'Thursday',
77+
'5': 'Friday',
78+
'6': 'Saturday'
79+
}
80+
81+
convert_datetime_days = {
82+
0:1,
83+
1:2,
84+
2:3,
85+
3:4,
86+
4:5,
87+
5:6,
88+
6:0
89+
}
90+
91+
# Validate
92+
if not 0 < len(date_input) < 11:
93+
raise ValueError("Must be 10 characters long")
94+
95+
# Get month
96+
m: int = int(date_input[0] + date_input[1])
97+
# Validate
98+
if not 0 < m < 13:
99+
raise ValueError("Month must be between 1 - 12")
100+
101+
sep_1:str = date_input[2]
102+
# Validate
103+
if sep_1 not in ["-","/"]:
104+
raise ValueError("Date seperator must be '-' or '/'")
105+
106+
# Get day
107+
d: int = int(date_input[3] + date_input[4])
108+
# Validate
109+
if not 0 < d < 32:
110+
raise ValueError("Date must be between 1 - 31")
111+
112+
# Get second seperator
113+
sep_2: str = date_input[5]
114+
# Validate
115+
if sep_2 not in ["-","/"]:
116+
raise ValueError("Date seperator must be '-' or '/'")
117+
118+
# Get year
119+
y: int = int(date_input[6] + date_input[7] + date_input[8] + date_input[9])
120+
# Arbitrary year range
121+
if not 45 < y < 8500:
122+
raise ValueError("Year out of range. There has to be some sort of limit...right?")
123+
124+
# Get datetime obj for validation
125+
dt_ck = datetime.date(int(y), int(m), int(d))
126+
127+
# Start math
128+
if m <= 2:
129+
y = y - 1
130+
m = m + 12
131+
# maths var
132+
c: int = int(str(y)[:2])
133+
k: int = int(str(y)[2:])
134+
t: int = int(2.6*m - 5.39)
135+
u: int = int(c / 4)
136+
v: int = int(k / 4)
137+
x: int = int(d + k)
138+
z: int = int(t + u + v + x)
139+
w: int = int(z - (2 * c))
140+
f: int = round(w%7)
141+
# End math
142+
143+
# Validate math
144+
if f != convert_datetime_days[dt_ck.weekday()]:
145+
raise AssertionError("The date was evaluated incorrectly. Contact developer.")
146+
147+
# Response
148+
response: str = f"Your date {date_input}, is a {days[str(f)]}!"
149+
return response
150+
151+
if __name__ == '__main__':
152+
import doctest
153+
doctest.testmod()
154+
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')
155+
parser.add_argument('date_input', type=str, help='Date as a string (mm-dd-yyyy or mm/dd/yyyy)')
156+
args = parser.parse_args()
157+
zeller(args.date_input)

0 commit comments

Comments
 (0)