Skip to content

Instantly share code, notes, and snippets.

@BioGeek
Last active September 15, 2017 11:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BioGeek/4984858 to your computer and use it in GitHub Desktop.
Save BioGeek/4984858 to your computer and use it in GitHub Desktop.
Algorithm that returns the day of the week for a given date. Works for the Gregorian calendar which began on September 14, 1752 up till December 31, 2299.Based on the description found at http://www.kungfoomanchu.com/z-creations/mentalcalculationofdate.pdf
import datetime
import calendar
months = [6, 2, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", "Sunday"]
centuries = {17: 5,
18: 3,
19: 1,
20: 0,
21: -2,
22: -4}
def day_of_week(day, month, year):
"""This algorithm is only valid for the Gregorian calendar,
which began on September 14, 1752, and up till December 31, 2299"""
if year <= 1752 and month <= 9 and day < 14:
raise RuntimeError("This algorithm is only valid for the Gregorian " + \
"calendar which began on September 14, 1752.")
if year >= 2300:
raise RuntimeError("This algorithm is only valid for the Gregorian " + \
"calendar up till December 31, 2299.")
# Take multiples of 28 from the the last 2 digits of the year
y = divmod(year, 100)[1] % 28
# Add a quarter of the nearest multiple of 4 below the number,
y += divmod(y, 4)[0]
# Take away 7 or multiples of 7. This leaves us the year code
y = y % 7
# The code for the month from the table above
m = months[month - 1]
# If it is a leap year AND the month is January or February, subtract 1
if is_leap_year(year) and month in [1,2]:
m -= 1
# Take away 7 or multiples of 7 from the day
d = day % 7
# Add the codes for the year, the month and the day
result = y + m + d
# Add 1 if the date is in the 1900s
result += centuries[divmod(year, 100)[0]]
# Take away 7 or multiples of 7
result = result % 7
# The final number indicates day of the week
return weekdays[result]
def is_leap_year(year):
# Leap years are the years evenly divisible by 4
# unless it ends in 00 and is a multiple of 400
if not year % 400:
return True
elif not year % 100:
return False
elif not year % 4:
return True
return False
# alternate solution using builtin functions
def day_of_week_builtin(day, month, year):
""" See http://stackoverflow.com/a/14941764/50065 by mgilson"""
c = calendar.weekday(year, month, day)
return calendar.day_name[c]
def date_generator(day, month, year):
"""Convenience function that yields (day, month, year) tuples"""
d = datetime.date(year, month, day)
while True:
d += datetime.timedelta(days=1)
yield d.day, d.month, d.year
if __name__ == '__main__':
# checking all days from the beginning of the Gregorian
# calendar till 2300
d = dategenerator(14, 9, 1752)
for day, month, year in d:
if year == 2300:
break
assert day_of_week(day, month, year) == day_of_week_builtin(day, month, year)
# checking my date of birth
print day_of_week(19, 5, 1978)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment