[Python-checkins] CVS: python/nondist/sandbox/datetime datetime.py,1.3,1.4 test_datetime.py,1.1,1.2

Tim Peters tim_one@users.sourceforge.net
Fri, 01 Mar 2002 14:42:30 -0800


Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory usw-pr-cvs1:/tmp/cvs-serv1524

Modified Files:
	datetime.py test_datetime.py 
Log Message:
Incorporate a pile of utility functions from Demo/classes/Dates.py, which
also assumes the Gregorian calender indefinitely extended.  In particular,
this gives us _date2num() and _num2date() utilities that establish a
bijection between datetime objects and a contiguous range of integers,
such that consecutive days are associated with consecutive integers.


Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** datetime.py	1 Mar 2002 22:19:41 -0000	1.3
--- datetime.py	1 Mar 2002 22:42:28 -0000	1.4
***************
*** 4,7 ****
--- 4,75 ----
  MAXYEAR = 9999  # XXX The design doc says 65535
  
+ # Utility functions, adapted from Python's Demo/classes/Dates.py, which
+ # also assumes the current Gregorian calendar indefinitely extended in
+ # both directions.
+ 
+ _DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+ 
+ _DAYS_BEFORE_MONTH = []
+ dbm = 0
+ for dim in _DAYS_IN_MONTH:
+     _DAYS_BEFORE_MONTH.append(dbm)
+     dbm = dbm + dim
+ del dbm, dim
+ 
+ def _is_leap(year):
+     "year -> 1 if leap year, else 0."
+     return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
+ 
+ def _days_in_year(year):
+     "year -> number of days in year (366 if a leap year, else 365)."
+     return 365 + _is_leap(year)
+ 
+ def _days_before_year(year):
+     "year -> number of days before January 1st of year."
+     return year*365 + (year+3)//4 - (year+99)//100 + (year+399)//400
+ 
+ def _days_in_month(month, year):
+     "month, year -> number of days in that month in that year."
+     assert 1 <= month <= 12, month
+     if month == 2 and _is_leap(year):
+         return 29
+     return _DAYS_IN_MONTH[month-1]
+ 
+ def _days_before_month(month, year):
+     "month, year -> number of days in year preceeding first day of month."
+     return _DAYS_BEFORE_MONTH[month-1] + (month > 2 and _is_leap(year))
+ 
+ def _date2num(date):
+     "datetime object -> day ordinal, considering 01-Jan-0000 as day 1."
+     assert isinstance(date, datetime)
+     return (_days_before_year(date.year) +
+             _days_before_month(date.month, date.year) +
+             date.day)
+ 
+ _DI400Y = _days_before_year(400)    # number of days in 400 years
+ 
+ def _num2date(n):
+     "day ordinal -> datetime object."
+ 
+     n400 = (n-1) // _DI400Y  # number of 400-year blocks preceding
+     year = n400 * 400
+     n -= n400 * _DI400Y
+ 
+     more = n // 365
+     dby = _days_before_year(more)
+     if dby >= n:
+         more -= 1
+         dby -= _days_in_year(more)
+     year += more
+     n -= dby
+ 
+     month = min(n//29 + 1, 12)
+     dbm = _days_before_month(month, year)
+     if dbm >= n:
+         month -= 1
+         dbm -= _days_in_month(month, year)
+ 
+     return datetime(year, month, n-dbm)
+ 
  class basetime(object):
      """Abstract date/time type.

Index: test_datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_datetime.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** test_datetime.py	1 Mar 2002 21:00:49 -0000	1.1
--- test_datetime.py	1 Mar 2002 22:42:28 -0000	1.2
***************
*** 27,30 ****
--- 27,39 ----
          self.assert_(dt2 > dt3)
  
+     def test_ordinal_conversions(self):
+         import datetime as _datetime
+         for year in range(_datetime.MINYEAR, _datetime.MAXYEAR + 1):
+             for month, day in (1, 1), (12, 31), (6, 17):
+                 base = datetime(year, month, day)
+                 ordinal = _datetime._date2num(base)
+                 derived = _datetime._num2date(ordinal)
+                 self.assertEqual(base, derived)
+ 
  def test_suite():
      s1 = unittest.makeSuite(TestDateTime, 'test')