Date arithmetic calculates dates by adding or subtracting intervals and finding the number of days between dates. Gregorian rules make this difficult because month lengths, leap years, missing year zero, and the 1582 calendar transition all matter. section 5.3
A Date implementation can evolve through two contrasting approaches:
- Loop day by day, using private methods for the next and previous dates. This handles positive and negative intervals but creates a new Date object on every iteration and becomes expensive for large differences. section 5.3.1
- Represent each date internally with a Julian day number. Adding days becomes integer addition, and the difference between dates becomes subtraction. section 5.3.2
- Convert between Julian numbers and Gregorian year, month, and day values through private conversion methods, preserving implementation hiding while introducing conversion cost for getters. section 5.3.2
Checking inverse operations
For September 2, 2025 and April 3, 2027, days_from returns 578. Adding 578 days to the first date produces the second; reversing the calculation returns −578 and recovers the first date. section 5.3.1
Listing 5.3 (Program 5.2 DateArithmetic-1): date.py (1 of 4; very inefficient!)
class Date:
_JANUARY = 1 #1
_FEBRUARY = 2 #1
_DECEMBER = 12 #1
#1
_GREGORIAN_START_YEAR = 1582 #1
_GREGORIAN_START_MONTH = 10 #1
_GREGORIAN_START_DATE = 15 #1
_JULIAN_END_DATE = 4 #1
#1
_DAYS_IN_MONTH = ( 31, 28, 31, 30, 31, 30, #1
31, 31, 30, 31, 30, 31 ) #1
def __init__(self, year, month, day):
self._year = year #2
self._month = month #2
self._day = day #2
@property
def year(self): return self._year #3
@property
def month(self): return self._month #3
@property
def day(self): return self._day #3
def __repr__(self):
date_string = f'{self.month}/{self.day}/'
if self.year > 0: date_string += str(self.year)
else: date_string += str(-self.year) + ' BCE'
return date_string
Inspect the loop-based Date implementation, including calendar constants, date stepping, and interval methods. section 5.3.1

