### Convert a year/month/date
### into a serial number
def day_number(*ymd):
d = day_number_(*ymd)
assert ymd == nth_date_(d), \
f"Round trip failed {ymd}" \
f" != nth_date({d})"
return d
def day_number_(y, m, d):
if m < 3:
y -= 1
m += 9
else:
m -= 3
return \
365*y +\
y//4 - y//100 + y//400 +\
30*m +\
(6*m + 5)//10 +\
d
def is_leap_year(y):
return day_number_(y, 2, 29) \
!= day_number_(y, 3, 1)
### Convert a serial number
### into a year/month/date
# This should never fail its assertion
def nth_date(d):
ymd = nth_date_(d)
assert d == day_number_(*ymd), \
f"Round trip failed {d}" \
f" != day_number{ymd}"
return ymd
def nth_date_(d):
d -= 1
(y, d) = date_divmod_365_2425(d)
(m, d) = date_divmod_30_6(d)
if m > 9:
y += 1
m -= 9
else:
m += 3
d += 1
return y, m, d
def date_divmod_365_2425(d):
c, d = divmod(4*d + 3, 146097)
d //= 4
y, d = divmod(4*d + 3, 1461)
d //= 4
return c*100 + y, d
def date_divmod_30_6(d):
m, d = divmod(10*d + 5, 306)
d //= 10
return m, d
### Pretty-print dates
### and serial numbers
days_of_week = (
"Mon", "Tues", "Wednes", "Thurs",
"Fri", "Satur", "Sun"
)
def print_header():
print(
" yyyy/mm/dd"
" #=> in Week"
" 0/3/1"
)
print(
" __________"
" _________"
" _______"
)
def print_day(*ymd ,d=None):
if d is None:
d = day_number(*ymd)
else:
ymd = nth_date(d)
print(
f" {ymd[0]: 05}",
f"/{ymd[1]:02}/{ymd[2]:02}"
if ymd[1:] != (2, 29)
else "*02*29",
" #=> {:>6}day".format(
days_of_week[(1 + d) % 7]
),
f" {d:8}",
sep=""
)
### Example
print("Gregorian Proleptic Calendar")
print()
print("Day Numbers")
print_header()
print_day(-4713, 11, 24)
print_day(0, 2, 29)
print_day(1970, 1, 1)
print_day(2000, 1, 1)
print()
print("Julian Zero")
print_header()
print_day(-4713, 11, 24)
print()
print("Anno Domini")
print_header()
print_day(0, 1, 1)
print_day(0, 2, 28)
print_day(0, 2, 29)
print_day(0, 3, 1)
print_day(1, 1, 1)
print_day(1, 2, 28)
print_day(1, 3, 1)
print()
print("Computer Epochs")
print_header()
print_day(1970, 1, 1)
print_day(2000, 1, 1)
print()
print("Leap Years")
print_header()
for y in (1900, 2000, 2020, 2100):
print_day(y, 2, 28)
if is_leap_year(y):
print_day(y, 2, 29)
print_day(y, 3, 1)
print()
print("Today")
print_header()
def today():
import time;
return time.localtime()[:3]
print_day(*today())
print()
print("Random Days Test")
print_header()
def print_random_day():
from random import randrange
print_day(d=randrange(0, 1000000))
for _ in range(10):
print_random_day()
print()