14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Class Date supplies date objects that support date arithmetic. 24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# 34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Date(month,day,year) returns a Date object. An instance prints as, 44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# e.g., 'Mon 16 Aug 1993'. 54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# 64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Addition, subtraction, comparison operators, min, max, and sorting 74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# all work as expected for date objects: int+date or date+int returns 84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# the date `int' days from `date'; date+date raises an exception; 94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# date-int returns the date `int' days before `date'; date2-date1 returns 104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# an integer, the number of days from date1 to date2; int-date raises an 114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# exception; date1 < date2 is true iff date1 occurs before date2 (& 124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# similarly for other comparisons); min(date1,date2) is the earlier of 134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# the two dates and max(date1,date2) the later; and date objects can be 144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# used as dictionary keys. 154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# 164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Date objects support one visible method, date.weekday(). This returns 174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# the day of the week the date falls on, as a string. 184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# 194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Date objects also have 4 read-only data attributes: 204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# .month in 1..12 214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# .day in 1..31 224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# .year int or long int 234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# .ord the ordinal of the date relative to an arbitrary staring point 244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# 254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# The Dates module also supplies function today(), which returns the 264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# current date as a date object. 274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# 284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Those entranced by calendar trivia will be disappointed, as no attempt 294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# has been made to accommodate the Julian (etc) system. On the other 304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# hand, at least this package knows that 2000 is a leap year but 2100 314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# isn't, and works fine for years with a hundred decimal digits <wink>. 324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Tim Peters tim@ksr.com 344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# not speaking for Kendall Square Research Corp 354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Adapted to Python 1.1 (where some hacks to overcome coercion are unnecessary) 374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# by Guido van Rossum 384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Note that as of Python 2.3, a datetime module is included in the stardard 404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# library. 414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# vi:set tabsize=8: 434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_MONTH_NAMES = [ 'January', 'February', 'March', 'April', 'May', 454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 'June', 'July', 'August', 'September', 'October', 464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 'November', 'December' ] 474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_DAY_NAMES = [ 'Friday', 'Saturday', 'Sunday', 'Monday', 494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 'Tuesday', 'Wednesday', 'Thursday' ] 504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_DAYS_IN_MONTH = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] 524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_DAYS_BEFORE_MONTH = [] 544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdbm = 0 554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfor dim in _DAYS_IN_MONTH: 564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _DAYS_BEFORE_MONTH.append(dbm) 574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm dbm = dbm + dim 584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdel dbm, dim 594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_INT_TYPES = type(1), type(1L) 614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _is_leap(year): # 1 if leap year, else 0 634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if year % 4 != 0: return 0 644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if year % 400 == 0: return 1 654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return year % 100 != 0 664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _days_in_year(year): # number of days in year 684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 365 + _is_leap(year) 694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _days_before_year(year): # number of days before year 714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return year*365L + (year+3)//4 - (year+99)//100 + (year+399)//400 724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _days_in_month(month, year): # number of days in month of year 744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if month == 2 and _is_leap(year): return 29 754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return _DAYS_IN_MONTH[month-1] 764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _days_before_month(month, year): # number of days in year before month 784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return _DAYS_BEFORE_MONTH[month-1] + (month > 2 and _is_leap(year)) 794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _date2num(date): # compute ordinal of date.month,day,year 814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return _days_before_year(date.year) + \ 824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _days_before_month(date.month, date.year) + \ 834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm date.day 844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_DI400Y = _days_before_year(400) # number of days in 400 years 864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _num2date(n): # return date with ordinal n 884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if type(n) not in _INT_TYPES: 894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise TypeError, 'argument must be integer: %r' % type(n) 904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ans = Date(1,1,1) # arguments irrelevant; just getting a Date obj 924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm del ans.ord, ans.month, ans.day, ans.year # un-initialize it 934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ans.ord = n 944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm n400 = (n-1)//_DI400Y # # of 400-year blocks preceding 964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm year, n = 400 * n400, n - _DI400Y * n400 974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm more = n // 365 984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm dby = _days_before_year(more) 994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if dby >= n: 1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm more = more - 1 1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm dby = dby - _days_in_year(more) 1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm year, n = year + more, int(n - dby) 1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: year = int(year) # chop to int, if it fits 1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except (ValueError, OverflowError): pass 1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm month = min(n//29 + 1, 12) 1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm dbm = _days_before_month(month, year) 1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if dbm >= n: 1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm month = month - 1 1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm dbm = dbm - _days_in_month(month, year) 1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ans.month, ans.day, ans.year = month, n-dbm, year 1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return ans 1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _num2day(n): # return weekday name of day with ordinal n 1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return _DAY_NAMES[ int(n % 7) ] 1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass Date: 1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, month, day, year): 1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not 1 <= month <= 12: 1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise ValueError, 'month must be in 1..12: %r' % (month,) 1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm dim = _days_in_month(month, year) 1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not 1 <= day <= dim: 1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise ValueError, 'day must be in 1..%r: %r' % (dim, day) 1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.month, self.day, self.year = month, day, year 1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.ord = _date2num(self) 1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # don't allow setting existing attributes 1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __setattr__(self, name, value): 1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.__dict__.has_key(name): 1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise AttributeError, 'read-only attribute ' + name 1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__dict__[name] = value 1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __cmp__(self, other): 1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return cmp(self.ord, other.ord) 1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # define a hash function so dates can be used as dictionary keys 1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __hash__(self): 1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return hash(self.ord) 1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # print as, e.g., Mon 16 Aug 1993 1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __repr__(self): 1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return '%.3s %2d %.3s %r' % ( 1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.weekday(), 1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.day, 1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _MONTH_NAMES[self.month-1], 1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.year) 1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Python 1.1 coerces neither int+date nor date+int 1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __add__(self, n): 1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if type(n) not in _INT_TYPES: 1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise TypeError, 'can\'t add %r to date' % type(n) 1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return _num2date(self.ord + n) 1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm __radd__ = __add__ # handle int+date 1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Python 1.1 coerces neither date-int nor date-date 1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __sub__(self, other): 1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if type(other) in _INT_TYPES: # date-int 1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return _num2date(self.ord - other) 1624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 1634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return self.ord - other.ord # date-date 1644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # complain about int-date 1664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __rsub__(self, other): 1674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise TypeError, 'Can\'t subtract date from integer' 1684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def weekday(self): 1704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return _num2day(self.ord) 1714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef today(): 1734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm import time 1744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm local = time.localtime(time.time()) 1754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return Date(local[1], local[2], local[0]) 1764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass DateTestError(Exception): 1784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 1794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test(firstyear, lastyear): 1814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm a = Date(9,30,1913) 1824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm b = Date(9,30,1914) 1834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if repr(a) != 'Tue 30 Sep 1913': 1844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, '__repr__ failure' 1854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if (not a < b) or a == b or a > b or b != b: 1864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, '__cmp__ failure' 1874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if a+365 != b or 365+a != b: 1884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, '__add__ failure' 1894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if b-a != 365 or b-365 != a: 1904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, '__sub__ failure' 1914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 1924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm x = 1 - a 1934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, 'int-date should have failed' 1944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except TypeError: 1954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 1964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 1974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm x = a + b 1984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, 'date+date should have failed' 1994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except TypeError: 2004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 2014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if a.weekday() != 'Tuesday': 2024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, 'weekday() failure' 2034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if max(a,b) is not b or min(a,b) is not a: 2044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, 'min/max failure' 2054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d = {a-1:b, b:a+1} 2064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if d[b-366] != b or d[a+(b-a)] != Date(10,1,1913): 2074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, 'dictionary failure' 2084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # verify date<->number conversions for first and last days for 2104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # all years in firstyear .. lastyear 2114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm lord = _days_before_year(firstyear) 2134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm y = firstyear 2144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while y <= lastyear: 2154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ford = lord + 1 2164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm lord = ford + _days_in_year(y) - 1 2174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm fd, ld = Date(1,1,y), Date(12,31,y) 2184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if (fd.ord,ld.ord) != (ford,lord): 2194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, ('date->num failed', y) 2204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm fd, ld = _num2date(ford), _num2date(lord) 2214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if (1,1,y,12,31,y) != \ 2224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm (fd.month,fd.day,fd.year,ld.month,ld.day,ld.year): 2234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DateTestError, ('num->date failed', y) 2244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm y = y + 1 2254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmif __name__ == '__main__': 2274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm test(1850, 2150) 228