[Python-checkins] CVS: python/nondist/sandbox/datetime datetime.py,1.21,1.22 test_datetime.py,1.12,1.13
Tim Peters
tim_one@users.sourceforge.net
Sat, 02 Mar 2002 22:11:56 -0800
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory usw-pr-cvs1:/tmp/cvs-serv5735
Modified Files:
datetime.py test_datetime.py
Log Message:
Get a start on a struct tm kinda-workalike that does principled, x-platform
normalization; doesn't have year 1970-2038 restrictions; and can construct
Unixish timestamps (floating seconds since 1970) for years before 1970 too.
Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -d -r1.21 -r1.22
*** datetime.py 3 Mar 2002 04:03:22 -0000 1.21
--- datetime.py 3 Mar 2002 06:11:54 -0000 1.22
***************
*** 92,95 ****
--- 92,151 ----
return year, month, n-dbm
+ # This is a start at a struct tm workalike. Goals:
+ #
+ # + Works the same way across platforms.
+ # + Handles all the fields datetime needs handled, without 1970-2038 glitches.
+ #
+ # Note: I suspect it's best if this flavor of tm does *not* try to
+ # second-guess timezones or DST. Instead fold whatever adjustments you want
+ # into the minutes argument (and the constructor will normalize).
+
+ _ORD1970 = _ymd2ord(1970, 1, 1) # base ordinal for UNIX epoch
+
+ class tmxxx:
+
+ ordinal = None
+
+ def __init__(self, year, month, day, hour=0, minute=0, second=0,
+ microsecond=0):
+ # Normalize all the inputs, and store the normalized values.
+ carry, microsecond = divmod(microsecond, 1000000)
+ second += carry
+ carry, second = divmod(second, 60)
+ minute += carry
+ carry, minute = divmod(minute, 60)
+ hour += carry
+ carry, hour = divmod(hour, 24)
+ day += carry
+ # That was easy. Now it gets muddy: the proper range for day
+ # can't be determined without knowing the correct month and year,
+ # but if day is, e.g., plus or minus a million, the current month
+ # and year values make no sense (and may also be out of bounds
+ # themselves).
+ # Saying 12 months == 1 year should be non-controversial.
+ carry, month = divmod(month-1, 12)
+ year += carry
+ month += 1
+ assert 1 <= month <= 12
+ # Now only day can be out of bounds. If it is, what to do is arguable,
+ # but at least the method here is principled and explainable.
+ if not 1 <= day <= _days_in_month(month, year):
+ # Note that the "if" test is for efficiency, not correctness:
+ # there's simply no need to do this dance if day is already in
+ # range, and it's an expensive dance.
+ self.ordinal = _ymd2ord(year, month, 1) + (day - 1)
+ year, month, day = _ord2ymd(self.ordinal)
+ self.year, self.month, self.day = year, month, day
+ self.hour, self.minute, self.second = hour, minute, second
+ self.microsecond = microsecond
+
+ def time(self):
+ "Return Unixish timestamp, as a float."
+ if self.ordinal is None:
+ self.ordinal = _ymd2ord(self.year, self.month, self.day)
+ days = self.ordinal - _ORD1970 # convert to UNIX epoch
+ seconds = ((days * 24. + self.hour)*60. + self.minute)*60.
+ return seconds + self.second + self.microsecond / 1e6
+
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.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** test_datetime.py 3 Mar 2002 02:50:52 -0000 1.12
--- test_datetime.py 3 Mar 2002 06:11:54 -0000 1.13
***************
*** 222,247 ****
# http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
ISO_LONG_YEARS_TABLE = """
! 4 32 60 88
! 9 37 65 93
! 15 43 71 99
! 20 48 76
26 54 82
! 105 133 161 189
! 111 139 167 195
! 116 144 172
! 122 150 178
128 156 184
! 201 229 257 285
! 207 235 263 291
! 212 240 268 296
! 218 246 274
224 252 280
! 303 331 359 387
! 308 336 364 392
! 314 342 370 398
! 320 348 376
325 353 381
"""
--- 222,247 ----
# http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
ISO_LONG_YEARS_TABLE = """
! 4 32 60 88
! 9 37 65 93
! 15 43 71 99
! 20 48 76
26 54 82
! 105 133 161 189
! 111 139 167 195
! 116 144 172
! 122 150 178
128 156 184
! 201 229 257 285
! 207 235 263 291
! 212 240 268 296
! 218 246 274
224 252 280
! 303 331 359 387
! 308 336 364 392
! 314 342 370 398
! 320 348 376
325 353 381
"""
***************
*** 257,260 ****
--- 257,273 ----
self.assertEqual(L, iso_long_years)
+ def test_tmxxx(self):
+ from datetime import tmxxx
+ for timestamp in 123456789.0, 987654321.0:
+ dt = datetime.utcfromtimestamp(timestamp)
+ # Mange the fields, but in such a way that normalization should
+ # restore them to dt's values.
+ tm = tmxxx(dt.year - 1, dt.month + 12, dt.day + 100,
+ dt.hour - 24*100, dt.minute - 3, dt.second + 12,
+ (3*60 - 12) * 1000000)
+ dt2 = datetime.new(tm.year, tm.month, tm.day, tm.hour, tm.minute,
+ tm.second, tm.microsecond, tzoffset=0)
+ self.assertEqual(dt, dt2)
+ self.assertEqual(timestamp, tm.time())
def test_suite():