#! /usr/bin/python
"""
Module: doomsday.py contains a simple implementation of the Doomsday
Algorithm published by John H. Conway in 1973.
Copyright 2013 by Charles Thayer
Released under Creative Commons Attribution-ShareAlike 3.0 Unported
http://creativecommons.org/licenses/by-sa/3.0/
"""
weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", \
"Friday", "Saturday"]
daysPerMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def dayOfWeek(yr, month, day):
"""
dayOfWeek() takes a Gregorian date as (year, month, day), and finds
the day of the week for that date.
"""
# Important constant
Feb_28 = 59
# Find the Doomsday Century Anchor
centuryAnchor = yr // 100
centuryAnchor = (16 - 2 * (centuryAnchor % 4)) % 7
# Is this a leap year?
# Basic presumption: No
leap = 0
# 1: If we're on a 4N year
# Calculate Doomsday number for year within century
yr = yr % 100
if not (yr % 4):
leapExcept = 1 if centuryAnchor == 2 else 0
# If year is not a Century boundary (i.e., not 0), leap = 1
leap = 1 if yr else leapExcept
# Get algorithm's Doomsday offset for the year
yrs_in_12 = yr % 12
iOffset = yr // 12 + yrs_in_12 + yrs_in_12 // 4 + centuryAnchor
# Get Day of Year
day_in_year = day + sum(daysPerMonth[:(month - 1)])
# Adjust dates after February 28 (Day 59) for leap day
if day_in_year > Feb_28:
day_in_year += leap
doomsday = Feb_28 + leap
# Make adjustments from Doomsday setting for the month
return weekdays[(35 + day_in_year - doomsday + iOffset) % 7]
def dayOfWeek2(yr, month, day):
"""
dayOfWeek2() takes a Gregorian date as (year, month, day), and finds
the day of the week for that date.
"""
# Find the Doomsday Century Anchor
centuryAnchor = yr // 100
centuryAnchor = (16 - 2 * (centuryAnchor % 4)) % 7
# Check leap year exception:
# - If Century Anchor is Tuesday, it's a leap year.
if centuryAnchor == 2:
leapExcept = 1
else:
leapExcept = 0
# Calculate Doomsday number for year within century
yr = yr % 100
yrs_in_12 = yr % 12
iOffset = yr // 12 + yrs_in_12 + yrs_in_12 // 4 + centuryAnchor
# Fill in monthPos offset to find the Doomsday by month
# a) 4/4, 6/6, 8/8, 10/10, 12/12
# b) "I work my 9 to 5 job at 7-11."
# c) The 0th day of March is Doomsday, so march backwards for a
# few weeks to get (2/7, 2/8), (1/3, 1/4).
# Case 1: Month >= 3 means no Leap year adjustment
if month >= 3:
monthPos = month
# Odd numbered months
if month % 2:
monthPos += 4
if month > 7:
# September and November (subtract 4)
# Already added 4, so subtract 1
# (month + 3) is 7 more than (month - 4)
monthPos -= 1
else: # January and February
monthPos = 3 if month == 1 else 0
# January and February need leap year adjustment
# Is this a leap year?
# 0: Basic presumption: No
leap = 0
# 1: If we're on a 4N year
# If year is not a Century boundary (i.e., not 0),
# leap = 1
# But if it is a Century boundary
# leap gets leapExcept (settled this question above)
if yr % 4 == 0:
leap = 1 if yr else leapExcept
monthPos = monthPos + leap
# Make adjustments from Doomsday setting for the month
return weekdays[(35 + day - monthPos + iOffset) % 7]
if __name__ == "__main__":
print dayOfWeek(1898, 1, 20)
print dayOfWeek2(1898, 1, 20)
print dayOfWeek(2000, 5, 15)
print dayOfWeek2(2000, 5, 15)
print dayOfWeek(1900, 5, 15)
print dayOfWeek2(1900, 5, 15)
print dayOfWeek(1700, 5, 15)
print dayOfWeek2(1700, 5, 15)
print dayOfWeek(1800, 5, 15)
print dayOfWeek2(1800, 5, 15)
print dayOfWeek(1642, 12, 25)
print dayOfWeek2(1642, 12, 25)