63 lines
1.9 KiB
Python
63 lines
1.9 KiB
Python
"""Day-of-week via Julian Day Number, handling Julian/Gregorian transition.
|
|
|
|
Dates before 1582-10-15 use the Julian calendar; on/after use Gregorian.
|
|
The gap 1582-10-05..14 did not exist, so those dates are invalid.
|
|
Month lengths (including leap-year February) are validated per calendar.
|
|
"""
|
|
def _julian_leap(y):
|
|
return y % 4 == 0
|
|
|
|
def _gregorian_leap(y):
|
|
return (y % 4 == 0 and y % 100 != 0) or (y % 400 == 0)
|
|
|
|
def _is_julian(y, m, d):
|
|
return (y, m, d) < (1582, 10, 15)
|
|
|
|
def _days_in_month(y, m, julian):
|
|
if m in (1, 3, 5, 7, 8, 10, 12):
|
|
return 31
|
|
if m in (4, 6, 9, 11):
|
|
return 30
|
|
leap = _julian_leap(y) if julian else _gregorian_leap(y)
|
|
return 29 if leap else 28
|
|
|
|
def _jdn_julian(y, m, d):
|
|
a = (14 - m) // 12
|
|
yy = y + 4800 - a
|
|
mm = m + 12 * a - 3
|
|
return d + (153 * mm + 2) // 5 + 365 * yy + yy // 4 - 32083
|
|
|
|
def _jdn_gregorian(y, m, d):
|
|
a = (14 - m) // 12
|
|
yy = y + 4800 - a
|
|
mm = m + 12 * a - 3
|
|
return d + (153 * mm + 2) // 5 + 365 * yy + yy // 4 - yy // 100 + yy // 400 - 32045
|
|
|
|
NAMES = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
|
|
|
def dow(y, m, d):
|
|
if not (1 <= m <= 12):
|
|
raise ValueError("invalid month")
|
|
julian = _is_julian(y, m, d)
|
|
# gap dates did not exist
|
|
if (1582, 10, 5) <= (y, m, d) <= (1582, 10, 14):
|
|
raise ValueError("date did not exist (Julian/Gregorian gap)")
|
|
if not (1 <= d <= _days_in_month(y, m, julian)):
|
|
raise ValueError("invalid day for month")
|
|
if julian:
|
|
jdn = _jdn_julian(y, m, d)
|
|
else:
|
|
jdn = _jdn_gregorian(y, m, d)
|
|
return NAMES[jdn % 7]
|
|
|
|
def main():
|
|
import sys
|
|
if len(sys.argv) != 4:
|
|
print("usage: zeller_dow.py YYYY MM DD"); return 2
|
|
y, m, d = int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3])
|
|
print(dow(y, m, d))
|
|
return 0
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|