from datetime import * from unittest import TestCase from operator import lt, le, gt, ge, eq, ne, truediv, floordiv, mod class TestTimeDelta(Static[TestCase]): def test_constructor(self): eq = self.assertEqual td = timedelta # Check keyword args to constructor eq( td(), td( weeks=0, days=0, hours=0, minutes=0, seconds=0, milliseconds=0, microseconds=0, ), ) eq(td(1), td(days=1)) eq(td(0, 1), td(seconds=1)) eq(td(0, 0, 1), td(microseconds=1)) eq(td(weeks=1), td(days=7)) eq(td(days=1), td(hours=24)) eq(td(hours=1), td(minutes=60)) eq(td(minutes=1), td(seconds=60)) eq(td(seconds=1), td(milliseconds=1000)) eq(td(milliseconds=1), td(microseconds=1000)) # Check float args to constructor eq(td(weeks=1.0 / 7), td(days=1)) eq(td(days=1.0 / 24), td(hours=1)) eq(td(hours=1.0 / 60), td(minutes=1)) eq(td(minutes=1.0 / 60), td(seconds=1)) eq(td(seconds=0.001), td(milliseconds=1)) eq(td(milliseconds=0.001), td(microseconds=1)) def test_computations(self): eq = self.assertEqual td = timedelta a = td(7) # One week b = td(0, 60) # One minute c = td(0, 0, 1000) # One millisecond eq(a + b + c, td(7, 60, 1000)) eq(a - b, td(6, 24 * 3600 - 60)) # eq(b.__rsub__(a), td(6, 24*3600 - 60)) eq(-a, td(-7)) eq(+a, td(7)) eq(-b, td(-1, 24 * 3600 - 60)) eq(-c, td(-1, 24 * 3600 - 1, 999000)) eq(abs(a), a) eq(abs(-a), a) eq(td(6, 24 * 3600), a) eq(td(0, 0, 60 * 1000000), b) eq(a * 10, td(70)) eq(a * 10, 10 * a) eq(a * 10, 10 * a) eq(b * 10, td(0, 600)) eq(10 * b, td(0, 600)) eq(b * 10, td(0, 600)) eq(c * 10, td(0, 0, 10000)) eq(10 * c, td(0, 0, 10000)) eq(c * 10, td(0, 0, 10000)) eq(a * -1, -a) eq(b * -2, -b - b) eq(c * -2, -c + -c) eq(b * (60 * 24), (b * 60) * 24) eq(b * (60 * 24), (60 * b) * 24) eq(c * 1000, td(0, 1)) eq(1000 * c, td(0, 1)) eq(a // 7, td(1)) eq(b // 10, td(0, 6)) eq(c // 1000, td(0, 0, 1)) eq(a // 10, td(0, 7 * 24 * 360)) eq(a // 3600000, td(0, 0, 7 * 24 * 1000)) eq(a / 0.5, td(14)) eq(b / 0.5, td(0, 120)) eq(a / 7, td(1)) eq(b / 10, td(0, 6)) eq(c / 1000, td(0, 0, 1)) eq(a / 10, td(0, 7 * 24 * 360)) eq(a / 3600000, td(0, 0, 7 * 24 * 1000)) # Multiplication by float us = td(microseconds=1) eq((3 * us) * 0.5, 2 * us) eq((5 * us) * 0.5, 2 * us) eq(0.5 * (3 * us), 2 * us) eq(0.5 * (5 * us), 2 * us) eq((-3 * us) * 0.5, -2 * us) eq((-5 * us) * 0.5, -2 * us) # TODO: check Python's Issue #23521 and possibly # incorporate the same fix here. For now a couple # tests are disabled. # Issue #23521 eq(td(seconds=1) * 0.123456, td(microseconds=123456)) # eq(td(seconds=1) * 0.6112295, td(microseconds=611229)) # Division by int and float eq((3 * us) / 2, 2 * us) eq((5 * us) / 2, 2 * us) eq((-3 * us) / 2.0, -2 * us) eq((-5 * us) / 2.0, -2 * us) eq((3 * us) / -2, -2 * us) eq((5 * us) / -2, -2 * us) eq((3 * us) / -2.0, -2 * us) eq((5 * us) / -2.0, -2 * us) for i in range(-10, 10): eq((i * us / 3) // us, round(i / 3)) for i in range(-10, 10): eq((i * us / -3) // us, round(i / -3)) # Issue #23521 # eq(td(seconds=1) / (1 / 0.6112295), td(microseconds=611229)) # Issue #11576 eq(td(999999999, 86399, 999999) - td(999999999, 86399, 999998), td(0, 0, 1)) eq(td(999999999, 1, 1) - td(999999999, 1, 0), td(0, 0, 1)) """ def test_disallowed_special(self): a = timedelta(42) NAN = 0. / 0. self.assertRaises(ValueError, a.__mul__, NAN) self.assertRaises(ValueError, a.__truediv__, NAN) """ def test_basic_attributes(self): days, seconds, us = 1, 7, 31 td = timedelta(days, seconds, us) self.assertEqual(td.days, days) self.assertEqual(td.seconds, seconds) self.assertEqual(td.microseconds, us) def test_total_seconds(self): td = timedelta(days=365) self.assertEqual(td.total_seconds(), 31536000.0) for total_seconds in [123456.789012, -123456.789012, 0.123456, 0, 1e6]: td = timedelta(seconds=total_seconds) self.assertEqual(td.total_seconds(), total_seconds) # Issue8644: Test that td.total_seconds() has the same # accuracy as td / timedelta(seconds=1). for ms in [-1, -2, -123]: td = timedelta(microseconds=ms) self.assertEqual(td.total_seconds(), td / timedelta(seconds=1)) def test_carries(self): t1 = timedelta( days=100, weeks=-7, hours=-24 * (100 - 49), minutes=-3, seconds=12, microseconds=(3 * 60 - 12) * 1e6 + 1, ) t2 = timedelta(microseconds=1) self.assertEqual(t1, t2) def test_hash_equality(self): t1 = timedelta( days=100, weeks=-7, hours=-24 * (100 - 49), minutes=-3, seconds=12, microseconds=(3 * 60 - 12) * 1000000, ) t2 = timedelta() self.assertEqual(hash(t1), hash(t2)) t1 += timedelta(weeks=7) t2 += timedelta(days=7 * 7) self.assertEqual(t1, t2) self.assertEqual(hash(t1), hash(t2)) d = {t1: 1} d[t2] = 2 self.assertEqual(len(d), 1) self.assertEqual(d[t1], 2) def test_compare(self): t1 = timedelta(2, 3, 4) t2 = timedelta(2, 3, 4) self.assertEqual(t1, t2) self.assertTrue(t1 <= t2) self.assertTrue(t1 >= t2) self.assertFalse(t1 != t2) self.assertFalse(t1 < t2) self.assertFalse(t1 > t2) for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): t2 = timedelta(*args) # this is larger than t1 self.assertTrue(t1 < t2) self.assertTrue(t2 > t1) self.assertTrue(t1 <= t2) self.assertTrue(t2 >= t1) self.assertTrue(t1 != t2) self.assertTrue(t2 != t1) self.assertFalse(t1 == t2) self.assertFalse(t2 == t1) self.assertFalse(t1 > t2) self.assertFalse(t2 < t1) self.assertFalse(t1 >= t2) self.assertFalse(t2 <= t1) def test_str(self): td = timedelta eq = self.assertEqual eq(str(td(1)), "1 day, 0:00:00") eq(str(td(-1)), "-1 day, 0:00:00") eq(str(td(2)), "2 days, 0:00:00") eq(str(td(-2)), "-2 days, 0:00:00") eq(str(td(hours=12, minutes=58, seconds=59)), "12:58:59") eq(str(td(hours=2, minutes=3, seconds=4)), "2:03:04") eq(str(td(weeks=-30, hours=23, minutes=12, seconds=34)), "-210 days, 23:12:34") eq(str(td(milliseconds=1)), "0:00:00.001000") eq(str(td(microseconds=3)), "0:00:00.000003") # Codon's timedelta has a smaller range than Python's # since it uses a pure microseconds representation, so # below case is not supported. """ eq(str(td(days=999999999, hours=23, minutes=59, seconds=59, microseconds=999999)), "999999999 days, 23:59:59.999999") """ def test_repr(self): td = timedelta self.assertEqual(repr(td(1)), "timedelta(days=1)") self.assertEqual(repr(td(10, 2)), "timedelta(days=10, seconds=2)") self.assertEqual( repr(td(-10, 2, 400000)), "timedelta(days=-10, seconds=2, microseconds=400000)", ) self.assertEqual(repr(td(seconds=60)), "timedelta(seconds=60)") self.assertEqual(repr(td()), "timedelta(0)") self.assertEqual(repr(td(microseconds=100)), "timedelta(microseconds=100)") self.assertEqual( repr(td(days=1, microseconds=100)), "timedelta(days=1, microseconds=100)" ) self.assertEqual( repr(td(seconds=1, microseconds=100)), "timedelta(seconds=1, microseconds=100)", ) def test_resolution_info(self): self.assertTrue(timedelta.max > timedelta.min) #self.assertEqual(timedelta.min, timedelta(-999999999)) #self.assertEqual(timedelta.max, timedelta(999999999, 24*3600-1, 1e6-1)) self.assertEqual(timedelta.resolution, timedelta(0, 0, 1)) """ def test_overflow(self): tiny = timedelta(microseconds=1) # timedelta.resolution td = timedelta.min + tiny td -= tiny # no problem self.assertRaises(OverflowError, td.__sub__, tiny) self.assertRaises(OverflowError, td.__add__, -tiny) td = timedelta.max - tiny td += tiny # no problem self.assertRaises(OverflowError, td.__add__, tiny) self.assertRaises(OverflowError, td.__sub__, -tiny) self.assertRaises(OverflowError, lambda: -timedelta.max) day = timedelta(1) self.assertRaises(OverflowError, day.__mul__, 10**9) self.assertRaises(OverflowError, day.__mul__, 1e9) self.assertRaises(OverflowError, day.__truediv__, 1e-20) self.assertRaises(OverflowError, day.__truediv__, 1e-10) self.assertRaises(OverflowError, day.__truediv__, 9e-10) def _test_overflow_special(self): day = timedelta(1) INF = 1. / 0. self.assertRaises(OverflowError, day.__mul__, INF) self.assertRaises(OverflowError, day.__mul__, -INF) """ def test_microsecond_rounding(self): td = timedelta eq = self.assertEqual # Single-field rounding. eq(td(milliseconds=0.4 / 1000), td(0)) # rounds to 0 eq(td(milliseconds=-0.4 / 1000), td(0)) # rounds to 0 eq(td(milliseconds=0.5 / 1000), td(microseconds=0)) eq(td(milliseconds=-0.5 / 1000), td(microseconds=-0)) eq(td(milliseconds=0.6 / 1000), td(microseconds=1)) eq(td(milliseconds=-0.6 / 1000), td(microseconds=-1)) eq(td(milliseconds=1.5 / 1000), td(microseconds=2)) eq(td(milliseconds=-1.5 / 1000), td(microseconds=-2)) eq(td(seconds=0.5 / 10 ** 6), td(microseconds=0)) eq(td(seconds=-0.5 / 10 ** 6), td(microseconds=-0)) eq(td(seconds=1 / 2 ** 7), td(microseconds=7812)) eq(td(seconds=-1 / 2 ** 7), td(microseconds=-7812)) # Rounding due to contributions from more than one field. us_per_hour = 3600e6 us_per_day = us_per_hour * 24 eq(td(days=0.4 / us_per_day), td(0)) eq(td(hours=0.2 / us_per_hour), td(0)) eq(td(days=0.4 / us_per_day, hours=0.2 / us_per_hour), td(microseconds=1)) eq(td(days=-0.4 / us_per_day), td(0)) eq(td(hours=-0.2 / us_per_hour), td(0)) eq(td(days=-0.4 / us_per_day, hours=-0.2 / us_per_hour), td(microseconds=-1)) # Test for a patch in Issue 8860 eq(td(microseconds=0.5), 0.5 * td(microseconds=1.0)) resolution = td(microseconds=1) # td.resolution eq(td(microseconds=0.5) // resolution, 0.5 * resolution // resolution) def test_massive_normalization(self): td = timedelta(microseconds=-1) self.assertEqual( (td.days, td.seconds, td.microseconds), (-1, 24 * 3600 - 1, 999999) ) def test_bool(self): self.assertTrue(timedelta(1)) self.assertTrue(timedelta(0, 1)) self.assertTrue(timedelta(0, 0, 1)) self.assertTrue(timedelta(microseconds=1)) self.assertFalse(timedelta(0)) def test_division(self): t = timedelta(hours=1, minutes=24, seconds=19) second = timedelta(seconds=1) self.assertEqual(t / second, 5059.0) self.assertEqual(t // second, 5059) t = timedelta(minutes=2, seconds=30) minute = timedelta(minutes=1) self.assertEqual(t / minute, 2.5) self.assertEqual(t // minute, 2) zerotd = timedelta(0) # self.assertRaises(ZeroDivisionError, truediv, t, zerotd) # self.assertRaises(ZeroDivisionError, floordiv, t, zerotd) def test_remainder(self): t = timedelta(minutes=2, seconds=30) minute = timedelta(minutes=1) r = t % minute self.assertEqual(r, timedelta(seconds=30)) t = timedelta(minutes=-2, seconds=30) r = t % minute self.assertEqual(r, timedelta(seconds=30)) zerotd = timedelta(0) # self.assertRaises(ZeroDivisionError, mod, t, zerotd) def test_divmod(self): t = timedelta(minutes=2, seconds=30) minute = timedelta(minutes=1) q, r = divmod(t, minute) self.assertEqual(q, 2) self.assertEqual(r, timedelta(seconds=30)) t = timedelta(minutes=-2, seconds=30) q, r = divmod(t, minute) self.assertEqual(q, -2) self.assertEqual(r, timedelta(seconds=30)) zerotd = timedelta(0) # self.assertRaises(ZeroDivisionError, divmod, t, zerotd) class TestDateOnly(Static[TestCase]): def test_delta_non_days_ignored(self): dt = date(2000, 1, 2) delta = timedelta(days=1, hours=2, minutes=3, seconds=4, microseconds=5) days = timedelta(delta.days) self.assertEqual(days, timedelta(1)) dt2 = dt + delta self.assertEqual(dt2, dt + days) dt2 = delta + dt self.assertEqual(dt2, dt + days) dt2 = dt - delta self.assertEqual(dt2, dt - days) delta = -delta days = timedelta(delta.days) self.assertEqual(days, timedelta(-2)) dt2 = dt + delta self.assertEqual(dt2, dt + days) dt2 = delta + dt self.assertEqual(dt2, dt + days) dt2 = dt - delta self.assertEqual(dt2, dt - days) class TestDate(Static[TestCase]): theclass: type def test_basic_attributes(self): dt = self.theclass(2002, 3, 1) self.assertEqual(dt.year, 2002) self.assertEqual(dt.month, 3) self.assertEqual(dt.day, 1) def test_ordinal_conversions(self): # Check some fixed values. for y, m, d, n in [ (1, 1, 1, 1), # calendar origin (1, 12, 31, 365), (2, 1, 1, 366), # first example from "Calendrical Calculations" (1945, 11, 12, 710347), ]: dt = self.theclass(y, m, d) self.assertEqual(n, dt.toordinal()) fromord = self.theclass.fromordinal(n) self.assertEqual(dt, fromord) if hasattr(fromord, "hour"): # if we're checking something fancier than a date, verify # the extra fields have been zeroed out self.assertEqual(fromord.hour, 0) self.assertEqual(fromord.minute, 0) self.assertEqual(fromord.second, 0) self.assertEqual(fromord.microsecond, 0) # Check first and last days of year spottily across the whole # range of years supported. for year in range(MINYEAR, MAXYEAR + 1, 7): # Verify (year, 1, 1) -> ordinal -> y, m, d is identity. d = self.theclass(year, 1, 1) n = d.toordinal() d2 = self.theclass.fromordinal(n) self.assertEqual(d, d2) # Verify that moving back a day gets to the end of year-1. if year > 1: d = self.theclass.fromordinal(n - 1) d2 = self.theclass(year - 1, 12, 31) self.assertEqual(d, d2) self.assertEqual(d2.toordinal(), n - 1) # Test every day in a leap-year and a non-leap year. dim = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] for year, isleap in (2000, True), (2002, False): n = self.theclass(year, 1, 1).toordinal() for month, maxday in zip(range(1, 13), dim): if month == 2 and isleap: maxday += 1 for day in range(1, maxday + 1): d = self.theclass(year, month, day) self.assertEqual(d.toordinal(), n) self.assertEqual(d, self.theclass.fromordinal(n)) n += 1 """ def test_extreme_ordinals(self): a = self.theclass.min a = self.theclass(a.year, a.month, a.day) # get rid of time parts aord = a.toordinal() b = a.fromordinal(aord) self.assertEqual(a, b) self.assertRaises(ValueError, lambda: a.fromordinal(aord - 1)) b = a + timedelta(days=1) self.assertEqual(b.toordinal(), aord + 1) self.assertEqual(b, self.theclass.fromordinal(aord + 1)) a = self.theclass.max a = self.theclass(a.year, a.month, a.day) # get rid of time parts aord = a.toordinal() b = a.fromordinal(aord) self.assertEqual(a, b) self.assertRaises(ValueError, lambda: a.fromordinal(aord + 1)) b = a - timedelta(days=1) self.assertEqual(b.toordinal(), aord - 1) self.assertEqual(b, self.theclass.fromordinal(aord - 1)) """ def test_bad_constructor_arguments(self): # bad years self.theclass(MINYEAR, 1, 1) # no exception self.theclass(MAXYEAR, 1, 1) # no exception def make(theclass, a, b, c): return self.theclass(a, b, c) self.assertRaises(ValueError, make(self.theclass, ...), MINYEAR - 1, 1, 1) self.assertRaises(ValueError, make(self.theclass, ...), MAXYEAR + 1, 1, 1) # bad months self.theclass(2000, 1, 1) # no exception self.theclass(2000, 12, 1) # no exception self.assertRaises(ValueError, make(self.theclass, ...), 2000, 0, 1) self.assertRaises(ValueError, make(self.theclass, ...), 2000, 13, 1) # bad days self.theclass(2000, 2, 29) # no exception self.theclass(2004, 2, 29) # no exception self.theclass(2400, 2, 29) # no exception self.assertRaises(ValueError, make(self.theclass, ...), 2000, 2, 30) self.assertRaises(ValueError, make(self.theclass, ...), 2001, 2, 29) self.assertRaises(ValueError, make(self.theclass, ...), 2100, 2, 29) self.assertRaises(ValueError, make(self.theclass, ...), 1900, 2, 29) self.assertRaises(ValueError, make(self.theclass, ...), 2000, 1, 0) self.assertRaises(ValueError, make(self.theclass, ...), 2000, 1, 32) def test_hash_equality(self): d = self.theclass(2000, 12, 31) # same thing e = self.theclass(2000, 12, 31) self.assertEqual(d, e) self.assertEqual(hash(d), hash(e)) dic = {d: 1} dic[e] = 2 self.assertEqual(len(dic), 1) self.assertEqual(dic[d], 2) self.assertEqual(dic[e], 2) d = self.theclass(2001, 1, 1) # same thing e = self.theclass(2001, 1, 1) self.assertEqual(d, e) self.assertEqual(hash(d), hash(e)) dic = {d: 1} dic[e] = 2 self.assertEqual(len(dic), 1) self.assertEqual(dic[d], 2) self.assertEqual(dic[e], 2) def test_computations(self): a = self.theclass(2002, 1, 31) b = self.theclass(1956, 1, 31) c = self.theclass(2001, 2, 1) diff = a - b self.assertEqual(diff.days, 46 * 365 + len(range(1956, 2002, 4))) self.assertEqual(diff.seconds, 0) self.assertEqual(diff.microseconds, 0) day = timedelta(1) week = timedelta(7) a = self.theclass(2002, 3, 2) self.assertEqual(a + day, self.theclass(2002, 3, 3)) self.assertEqual(day + a, self.theclass(2002, 3, 3)) self.assertEqual(a - day, self.theclass(2002, 3, 1)) self.assertEqual(-day + a, self.theclass(2002, 3, 1)) self.assertEqual(a + week, self.theclass(2002, 3, 9)) self.assertEqual(a - week, self.theclass(2002, 2, 23)) self.assertEqual(a + 52 * week, self.theclass(2003, 3, 1)) self.assertEqual(a - 52 * week, self.theclass(2001, 3, 3)) self.assertEqual((a + week) - a, week) self.assertEqual((a + day) - a, day) self.assertEqual((a - week) - a, -week) self.assertEqual((a - day) - a, -day) self.assertEqual(a - (a + week), -week) self.assertEqual(a - (a + day), -day) self.assertEqual(a - (a - week), week) self.assertEqual(a - (a - day), day) self.assertEqual(c - (c - day), day) """ # Add/sub ints or floats should be illegal for i in 1, 1.0: self.assertRaises(TypeError, lambda: a+i) self.assertRaises(TypeError, lambda: a-i) self.assertRaises(TypeError, lambda: i+a) self.assertRaises(TypeError, lambda: i-a) # delta - date is senseless. self.assertRaises(TypeError, lambda: day - a) # mixing date and (delta or date) via * or // is senseless self.assertRaises(TypeError, lambda: day * a) self.assertRaises(TypeError, lambda: a * day) self.assertRaises(TypeError, lambda: day // a) self.assertRaises(TypeError, lambda: a // day) self.assertRaises(TypeError, lambda: a * a) self.assertRaises(TypeError, lambda: a // a) # date + date is senseless self.assertRaises(TypeError, lambda: a + a) """ """ def test_overflow(self): tiny = self.theclass.resolution for delta in [tiny, timedelta(1), timedelta(2)]: dt = self.theclass.min + delta dt -= delta # no problem self.assertRaises(OverflowError, dt.__sub__, delta) self.assertRaises(OverflowError, dt.__add__, -delta) dt = self.theclass.max - delta dt += delta # no problem self.assertRaises(OverflowError, dt.__add__, delta) self.assertRaises(OverflowError, dt.__sub__, -delta) """ def test_fromtimestamp(self): import time # Try an arbitrary fixed value. year, month, day = 1999, 9, 19 ts = time.mktime((year, month, day, 0, 0, 0, 0, 0, -1)) d = self.theclass.fromtimestamp(ts) self.assertEqual(d.year, year) self.assertEqual(d.month, month) self.assertEqual(d.day, day) def test_today(self): import time # We claim that today() is like fromtimestamp(time.time()), so # prove it. today = self.theclass.today() todayagain = today for dummy in range(3): today = self.theclass.today() ts = time.time() todayagain = self.theclass.fromtimestamp(ts) if today == todayagain: break # There are several legit reasons that could fail: # 1. It recently became midnight, between the today() and the # time() calls. # 2. The platform time() has such fine resolution that we'll # never get the same value twice. # 3. The platform time() has poor resolution, and we just # happened to call today() right before a resolution quantum # boundary. # 4. The system clock got fiddled between calls. # In any case, wait a little while and try again. time.sleep(0.1) # It worked or it didn't. If it didn't, assume it's reason #2, and # let the test pass if they're within half a second of each other. if today != todayagain: self.assertAlmostEqual(todayagain, today, delta=timedelta(seconds=0.5)) def test_weekday(self): for i in range(7): # March 4, 2002 is a Monday self.assertEqual(self.theclass(2002, 3, 4 + i).weekday(), i) self.assertEqual(self.theclass(2002, 3, 4 + i).isoweekday(), i + 1) # January 2, 1956 is a Monday self.assertEqual(self.theclass(1956, 1, 2 + i).weekday(), i) self.assertEqual(self.theclass(1956, 1, 2 + i).isoweekday(), i + 1) def test_isocalendar(self): # Check examples from # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm week_mondays = [ ((2003, 12, 22), (2003, 52, 1)), ((2003, 12, 29), (2004, 1, 1)), ((2004, 1, 5), (2004, 2, 1)), ((2009, 12, 21), (2009, 52, 1)), ((2009, 12, 28), (2009, 53, 1)), ((2010, 1, 4), (2010, 1, 1)), ] test_cases = [] for cal_date, iso_date in week_mondays: base_date = self.theclass(*cal_date) # Adds one test case for every day of the specified weeks for i in range(7): new_date = base_date + timedelta(i) new_iso = iso_date[0:2] + (iso_date[2] + i,) test_cases.append((new_date, new_iso)) for d, exp_iso in test_cases: self.assertEqual(d.isocalendar(), exp_iso) # Check that the tuple contents are accessible by field name t = d.isocalendar() self.assertEqual((t.year, t.week, t.weekday), exp_iso) def test_iso_long_years(self): # Calculate long ISO years and compare to table from # 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 """ iso_long_years = sorted(map(int, ISO_LONG_YEARS_TABLE.split())) L = [] for i in range(400): d = self.theclass(2000 + i, 12, 31).isocalendar() d1 = self.theclass(1600 + i, 12, 31).isocalendar() self.assertEqual((d.week, d.weekday), (d1.week, d1.weekday)) if d.week == 53: L.append(i) self.assertEqual(L, iso_long_years) def test_isoformat(self): t = self.theclass(2, 3, 2) self.assertEqual(t.isoformat(), "0002-03-02") def test_ctime(self): t = self.theclass(2002, 3, 2) self.assertEqual(t.ctime(), "Sat Mar 2 00:00:00 2002") def test_resolution_info(self): self.assertTrue(self.theclass.max > self.theclass.min) """ def test_extreme_timedelta(self): big = self.theclass.max - self.theclass.min # 3652058 days, 23 hours, 59 minutes, 59 seconds, 999999 microseconds n = (big.days*24*3600 + big.seconds)*1000000 + big.microseconds # n == 315537897599999999 ~= 2**58.13 justasbig = timedelta(0, 0, n) self.assertEqual(big, justasbig) self.assertEqual(self.theclass.min + big, self.theclass.max) self.assertEqual(self.theclass.max - big, self.theclass.min) """ def test_timetuple(self): from time import struct_time for i in range(7): # January 2, 1956 is a Monday (0) d = self.theclass(1956, 1, 2 + i) t = d.timetuple() self.assertEqual(t, struct_time(1956, 1, 2 + i, 0, 0, 0, i, 2 + i, -1)) # February 1, 1956 is a Wednesday (2) d = self.theclass(1956, 2, 1 + i) t = d.timetuple() self.assertEqual( t, struct_time(1956, 2, 1 + i, 0, 0, 0, (2 + i) % 7, 32 + i, -1) ) # March 1, 1956 is a Thursday (3), and is the 31+29+1 = 61st day # of the year. d = self.theclass(1956, 3, 1 + i) t = d.timetuple() self.assertEqual( t, struct_time(1956, 3, 1 + i, 0, 0, 0, (3 + i) % 7, 61 + i, -1) ) self.assertEqual(t.tm_year, 1956) self.assertEqual(t.tm_mon, 3) self.assertEqual(t.tm_mday, 1 + i) self.assertEqual(t.tm_hour, 0) self.assertEqual(t.tm_min, 0) self.assertEqual(t.tm_sec, 0) self.assertEqual(t.tm_wday, (3 + i) % 7) self.assertEqual(t.tm_yday, 61 + i) self.assertEqual(t.tm_isdst, -1) def test_compare(self): t1 = self.theclass(2, 3, 4) t2 = self.theclass(2, 3, 4) self.assertEqual(t1, t2) self.assertTrue(t1 <= t2) self.assertTrue(t1 >= t2) self.assertFalse(t1 != t2) self.assertFalse(t1 < t2) self.assertFalse(t1 > t2) for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): t2 = self.theclass(*args) # this is larger than t1 self.assertTrue(t1 < t2) self.assertTrue(t2 > t1) self.assertTrue(t1 <= t2) self.assertTrue(t2 >= t1) self.assertTrue(t1 != t2) self.assertTrue(t2 != t1) self.assertFalse(t1 == t2) self.assertFalse(t2 == t1) self.assertFalse(t1 > t2) self.assertFalse(t2 < t1) self.assertFalse(t1 >= t2) self.assertFalse(t2 <= t1) """ for badarg in OTHERSTUFF: self.assertEqual(t1 == badarg, False) self.assertEqual(t1 != badarg, True) self.assertEqual(badarg == t1, False) self.assertEqual(badarg != t1, True) self.assertRaises(TypeError, lambda: t1 < badarg) self.assertRaises(TypeError, lambda: t1 > badarg) self.assertRaises(TypeError, lambda: t1 >= badarg) self.assertRaises(TypeError, lambda: badarg <= t1) self.assertRaises(TypeError, lambda: badarg < t1) self.assertRaises(TypeError, lambda: badarg > t1) self.assertRaises(TypeError, lambda: badarg >= t1) """ def test_bool(self): # All dates are considered true. # self.assertTrue(self.theclass.min) # self.assertTrue(self.theclass.max) self.assertTrue(self.theclass(1, 1, 1)) def test_replace(self): cls = self.theclass args = (1, 2, 3) base = cls(*args) self.assertEqual(base, base.replace()) self.assertEqual(base.replace(year=2), cls(2, 2, 3)) self.assertEqual(base.replace(month=3), cls(1, 3, 3)) self.assertEqual(base.replace(day=4), cls(1, 2, 4)) # Out of bounds. base = cls(2000, 2, 29) self.assertRaises(ValueError, base.replace, year=2001) def test_fromisoformat(self): # Test that isoformat() is reversible base_dates = [ (1, 1, 1), (1000, 2, 14), (1900, 1, 1), (2000, 2, 29), (2004, 11, 12), (2004, 4, 3), (2017, 5, 30), ] for dt_tuple in base_dates: dt = self.theclass(*dt_tuple) dt_str = dt.isoformat() dt_rt = self.theclass.fromisoformat(dt.isoformat()) self.assertEqual(dt, dt_rt) def test_fromisoformat_fails(self): # Test that fromisoformat() fails on invalid values bad_strs = [ "", # Empty string "\ud800", # bpo-34454: Surrogate code point "009-03-04", # Not 10 characters "123456789", # Not a date "200a-12-04", # Invalid character in year "2009-1a-04", # Invalid character in month "2009-12-0a", # Invalid character in day "2009-01-32", # Invalid day "2009-02-29", # Invalid leap day "20090228", # Valid ISO8601 output not from isoformat() "2009\ud80002\ud80028", # Separators are surrogate codepoints ] for bad_str in bad_strs: self.assertRaises(ValueError, self.theclass.fromisoformat, bad_str) def test_fromisocalendar(self): # For each test case, assert that fromisocalendar is the # inverse of the isocalendar function dates = [ (2016, 4, 3), (2005, 1, 2), # (2004, 53, 7) (2008, 12, 30), # (2009, 1, 2) (2010, 1, 2), # (2009, 53, 6) (2009, 12, 31), # (2009, 53, 4) (1900, 1, 1), # Unusual non-leap year (year % 100 == 0) (1900, 12, 31), (2000, 1, 1), # Unusual leap year (year % 400 == 0) (2000, 12, 31), (2004, 1, 1), # Leap year (2004, 12, 31), (1, 1, 1), (9999, 12, 31), (MINYEAR, 1, 1), (MAXYEAR, 12, 31), ] for datecomps in dates: dobj = self.theclass(*datecomps) isocal = dobj.isocalendar() d_roundtrip = self.theclass.fromisocalendar(*isocal) self.assertEqual(dobj, d_roundtrip) def test_fromisocalendar_value_errors(self): isocals = [ (2019, 0, 1), (2019, -1, 1), (2019, 54, 1), (2019, 1, 0), (2019, 1, -1), (2019, 1, 8), (2019, 53, 1), (10000, 1, 1), (0, 1, 1), (9999999, 1, 1), (2 << 32, 1, 1), (2019, 2 << 32, 1), (2019, 1, 2 << 32), ] for isocal in isocals: self.assertRaises(ValueError, self.theclass.fromisocalendar, *isocal) class TestDateTime(Static[TestDate[theclass]]): theclass: type def test_basic_attributes(self): dt = self.theclass(2002, 3, 1, 12, 0) self.assertEqual(dt.year, 2002) self.assertEqual(dt.month, 3) self.assertEqual(dt.day, 1) self.assertEqual(dt.hour, 12) self.assertEqual(dt.minute, 0) self.assertEqual(dt.second, 0) self.assertEqual(dt.microsecond, 0) def test_basic_attributes_nonzero(self): # Make sure all attributes are non-zero so bugs in # bit-shifting access show up. dt = self.theclass(2002, 3, 1, 12, 59, 59, 8000) self.assertEqual(dt.year, 2002) self.assertEqual(dt.month, 3) self.assertEqual(dt.day, 1) self.assertEqual(dt.hour, 12) self.assertEqual(dt.minute, 59) self.assertEqual(dt.second, 59) self.assertEqual(dt.microsecond, 8000) def test_isoformat(self): t = self.theclass(1, 2, 3, 4, 5, 1, 123) self.assertEqual(t.isoformat(), "0001-02-03T04:05:01.000123") self.assertEqual(t.isoformat("T"), "0001-02-03T04:05:01.000123") self.assertEqual(t.isoformat(" "), "0001-02-03 04:05:01.000123") self.assertEqual(t.isoformat("\x00"), "0001-02-03\x0004:05:01.000123") # bpo-34482: Check that surrogates are handled properly. self.assertEqual(t.isoformat("\ud800"), "0001-02-03\ud80004:05:01.000123") self.assertEqual(t.isoformat(timespec="hours"), "0001-02-03T04") self.assertEqual(t.isoformat(timespec="minutes"), "0001-02-03T04:05") self.assertEqual(t.isoformat(timespec="seconds"), "0001-02-03T04:05:01") self.assertEqual( t.isoformat(timespec="milliseconds"), "0001-02-03T04:05:01.000" ) self.assertEqual( t.isoformat(timespec="microseconds"), "0001-02-03T04:05:01.000123" ) self.assertEqual(t.isoformat(timespec="auto"), "0001-02-03T04:05:01.000123") self.assertEqual(t.isoformat(sep=" ", timespec="minutes"), "0001-02-03 04:05") # str is ISO format with the separator forced to a blank. self.assertEqual(str(t), "0001-02-03 04:05:01.000123") # t = self.theclass(1, 2, 3, 4, 5, 1, 999500, tzinfo=timezone.utc) # self.assertEqual(t.isoformat(timespec='milliseconds'), "0001-02-03T04:05:01.999+00:00") t = self.theclass(1, 2, 3, 4, 5, 1, 999500) self.assertEqual( t.isoformat(timespec="milliseconds"), "0001-02-03T04:05:01.999" ) t = self.theclass(1, 2, 3, 4, 5, 1) self.assertEqual(t.isoformat(timespec="auto"), "0001-02-03T04:05:01") self.assertEqual( t.isoformat(timespec="milliseconds"), "0001-02-03T04:05:01.000" ) self.assertEqual( t.isoformat(timespec="microseconds"), "0001-02-03T04:05:01.000000" ) t = self.theclass(2, 3, 2) self.assertEqual(t.isoformat(), "0002-03-02T00:00:00") self.assertEqual(t.isoformat("T"), "0002-03-02T00:00:00") self.assertEqual(t.isoformat(" "), "0002-03-02 00:00:00") # str is ISO format with the separator forced to a blank. self.assertEqual(str(t), "0002-03-02 00:00:00") # ISO format with timezone # tz = FixedOffset(timedelta(seconds=16), 'XXX') # t = self.theclass(2, 3, 2, tzinfo=tz) # self.assertEqual(t.isoformat(), "0002-03-02T00:00:00+00:00:16") """ def test_isoformat_timezone(self): tzoffsets = [ ('05:00', timedelta(hours=5)), ('02:00', timedelta(hours=2)), ('06:27', timedelta(hours=6, minutes=27)), ('12:32:30', timedelta(hours=12, minutes=32, seconds=30)), ('02:04:09.123456', timedelta(hours=2, minutes=4, seconds=9, microseconds=123456)) ] tzinfos = [ ('', None), ('+00:00', timezone.utc), ('+00:00', timezone(timedelta(0))), ] tzinfos += [ (prefix + expected, timezone(sign * td)) for expected, td in tzoffsets for prefix, sign in [('-', -1), ('+', 1)] ] dt_base = self.theclass(2016, 4, 1, 12, 37, 9) exp_base = '2016-04-01T12:37:09' for exp_tz, tzi in tzinfos: dt = dt_base.replace(tzinfo=tzi) exp = exp_base + exp_tz with self.subTest(tzi=tzi): assert dt.isoformat() == exp """ """ def test_more_ctime(self): # Test fields that TestDate doesn't touch. import time t = self.theclass(2002, 3, 2, 18, 3, 5, 123) self.assertEqual(t.ctime(), "Sat Mar 2 18:03:05 2002") # Oops! The next line fails on Win2K under MSVC 6, so it's commented # out. The difference is that t.ctime() produces " 2" for the day, # but platform ctime() produces "02" for the day. According to # C99, t.ctime() is correct here. # self.assertEqual(t.ctime(), time.ctime(time.mktime(t.timetuple()))) # So test a case where that difference doesn't matter. t = self.theclass(2002, 3, 22, 18, 3, 5, 123) self.assertEqual(t.ctime(), time.ctime(time.mktime(t.timetuple()))) """ def test_tz_independent_comparing(self): dt1 = self.theclass(2002, 3, 1, 9, 0, 0) dt2 = self.theclass(2002, 3, 1, 10, 0, 0) dt3 = self.theclass(2002, 3, 1, 9, 0, 0) self.assertEqual(dt1, dt3) self.assertTrue(dt2 > dt3) # Make sure comparison doesn't forget microseconds, and isn't done # via comparing a float timestamp (an IEEE double doesn't have enough # precision to span microsecond resolution across years 1 through 9999, # so comparing via timestamp necessarily calls some distinct values # equal). dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998) us = timedelta(microseconds=1) dt2 = dt1 + us self.assertEqual(dt2 - dt1, us) self.assertTrue(dt1 < dt2) def test_bad_constructor_arguments(self): # bad years self.theclass(MINYEAR, 1, 1) # no exception self.theclass(MAXYEAR, 1, 1) # no exception make_dt1 = lambda a, b, c: self.theclass(a, b, c) make_dt2 = lambda a, b, c, d: self.theclass(a, b, c, d) make_dt3 = lambda a, b, c, d, e: self.theclass(a, b, c, d, e) make_dt4 = lambda a, b, c, d, e, f: self.theclass(a, b, c, d, e, f) make_dt5 = lambda a, b, c, d, e, f, g: self.theclass(a, b, c, d, e, f, g) self.assertRaises(ValueError, make_dt1, MINYEAR - 1, 1, 1) self.assertRaises(ValueError, make_dt1, MAXYEAR + 1, 1, 1) # bad months self.theclass(2000, 1, 1) # no exception self.theclass(2000, 12, 1) # no exception self.assertRaises(ValueError, make_dt1, 2000, 0, 1) self.assertRaises(ValueError, make_dt1, 2000, 13, 1) # bad days self.theclass(2000, 2, 29) # no exception self.theclass(2004, 2, 29) # no exception self.theclass(2400, 2, 29) # no exception self.assertRaises(ValueError, make_dt1, 2000, 2, 30) self.assertRaises(ValueError, make_dt1, 2001, 2, 29) self.assertRaises(ValueError, make_dt1, 2100, 2, 29) self.assertRaises(ValueError, make_dt1, 1900, 2, 29) self.assertRaises(ValueError, make_dt1, 2000, 1, 0) self.assertRaises(ValueError, make_dt1, 2000, 1, 32) # bad hours self.theclass(2000, 1, 31, 0) # no exception self.theclass(2000, 1, 31, 23) # no exception self.assertRaises(ValueError, make_dt2, 2000, 1, 31, -1) self.assertRaises(ValueError, make_dt2, 2000, 1, 31, 24) # bad minutes self.theclass(2000, 1, 31, 23, 0) # no exception self.theclass(2000, 1, 31, 23, 59) # no exception self.assertRaises(ValueError, make_dt3, 2000, 1, 31, 23, -1) self.assertRaises(ValueError, make_dt3, 2000, 1, 31, 23, 60) # bad seconds self.theclass(2000, 1, 31, 23, 59, 0) # no exception self.theclass(2000, 1, 31, 23, 59, 59) # no exception self.assertRaises(ValueError, make_dt4, 2000, 1, 31, 23, 59, -1) self.assertRaises(ValueError, make_dt4, 2000, 1, 31, 23, 59, 60) # bad microseconds self.theclass(2000, 1, 31, 23, 59, 59, 0) # no exception self.theclass(2000, 1, 31, 23, 59, 59, 999999) # no exception self.assertRaises(ValueError, make_dt5, 2000, 1, 31, 23, 59, 59, -1) self.assertRaises(ValueError, make_dt5, 2000, 1, 31, 23, 59, 59, 1000000) """ # bad fold self.assertRaises(ValueError, self.theclass, 2000, 1, 31, fold=-1) self.assertRaises(ValueError, self.theclass, 2000, 1, 31, fold=2) # Positional fold: self.assertRaises(TypeError, self.theclass, 2000, 1, 31, 23, 59, 59, 0, None, 1) """ def test_hash_equality(self): d = self.theclass(2000, 12, 31, 23, 30, 17) e = self.theclass(2000, 12, 31, 23, 30, 17) self.assertEqual(d, e) self.assertEqual(hash(d), hash(e)) dic = {d: 1} dic[e] = 2 self.assertEqual(len(dic), 1) self.assertEqual(dic[d], 2) self.assertEqual(dic[e], 2) d = self.theclass(2001, 1, 1, 0, 5, 17) e = self.theclass(2001, 1, 1, 0, 5, 17) self.assertEqual(d, e) self.assertEqual(hash(d), hash(e)) dic = {d: 1} dic[e] = 2 self.assertEqual(len(dic), 1) self.assertEqual(dic[d], 2) self.assertEqual(dic[e], 2) def test_computations(self): a = self.theclass(2002, 1, 31) b = self.theclass(1956, 1, 31) diff = a - b self.assertEqual(diff.days, 46 * 365 + len(range(1956, 2002, 4))) self.assertEqual(diff.seconds, 0) self.assertEqual(diff.microseconds, 0) a = self.theclass(2002, 3, 2, 17, 6) millisec = timedelta(0, 0, 1000) hour = timedelta(0, 3600) day = timedelta(1) week = timedelta(7) self.assertEqual(a + hour, self.theclass(2002, 3, 2, 18, 6)) self.assertEqual(hour + a, self.theclass(2002, 3, 2, 18, 6)) self.assertEqual(a + 10 * hour, self.theclass(2002, 3, 3, 3, 6)) self.assertEqual(a - hour, self.theclass(2002, 3, 2, 16, 6)) self.assertEqual(-hour + a, self.theclass(2002, 3, 2, 16, 6)) self.assertEqual(a - hour, a + -hour) self.assertEqual(a - 20 * hour, self.theclass(2002, 3, 1, 21, 6)) self.assertEqual(a + day, self.theclass(2002, 3, 3, 17, 6)) self.assertEqual(a - day, self.theclass(2002, 3, 1, 17, 6)) self.assertEqual(a + week, self.theclass(2002, 3, 9, 17, 6)) self.assertEqual(a - week, self.theclass(2002, 2, 23, 17, 6)) self.assertEqual(a + 52 * week, self.theclass(2003, 3, 1, 17, 6)) self.assertEqual(a - 52 * week, self.theclass(2001, 3, 3, 17, 6)) self.assertEqual((a + week) - a, week) self.assertEqual((a + day) - a, day) self.assertEqual((a + hour) - a, hour) self.assertEqual((a + millisec) - a, millisec) self.assertEqual((a - week) - a, -week) self.assertEqual((a - day) - a, -day) self.assertEqual((a - hour) - a, -hour) self.assertEqual((a - millisec) - a, -millisec) self.assertEqual(a - (a + week), -week) self.assertEqual(a - (a + day), -day) self.assertEqual(a - (a + hour), -hour) self.assertEqual(a - (a + millisec), -millisec) self.assertEqual(a - (a - week), week) self.assertEqual(a - (a - day), day) self.assertEqual(a - (a - hour), hour) self.assertEqual(a - (a - millisec), millisec) self.assertEqual( a + (week + day + hour + millisec), self.theclass(2002, 3, 10, 18, 6, 0, 1000), ) self.assertEqual( a + (week + day + hour + millisec), (((a + week) + day) + hour) + millisec ) self.assertEqual( a - (week + day + hour + millisec), self.theclass(2002, 2, 22, 16, 5, 59, 999000), ) self.assertEqual( a - (week + day + hour + millisec), (((a - week) - day) - hour) - millisec ) """ # Add/sub ints or floats should be illegal for i in 1, 1.0: self.assertRaises(TypeError, lambda: a+i) self.assertRaises(TypeError, lambda: a-i) self.assertRaises(TypeError, lambda: i+a) self.assertRaises(TypeError, lambda: i-a) # delta - datetime is senseless. self.assertRaises(TypeError, lambda: day - a) # mixing datetime and (delta or datetime) via * or // is senseless self.assertRaises(TypeError, lambda: day * a) self.assertRaises(TypeError, lambda: a * day) self.assertRaises(TypeError, lambda: day // a) self.assertRaises(TypeError, lambda: a // day) self.assertRaises(TypeError, lambda: a * a) self.assertRaises(TypeError, lambda: a // a) # datetime + datetime is senseless self.assertRaises(TypeError, lambda: a + a) """ def test_more_compare(self): # The test_compare() inherited from TestDate covers the error cases. # We just want to test lexicographic ordering on the members datetime # has that date lacks. args = (2000, 11, 29, 20, 58, 16, 999998) newargsx = [ (2001, 11, 29, 20, 58, 16, 999998), (2000, 12, 29, 20, 58, 16, 999998), (2000, 11, 30, 20, 58, 16, 999998), (2000, 11, 29, 21, 58, 16, 999998), (2000, 11, 29, 20, 59, 16, 999998), (2000, 11, 29, 20, 58, 17, 999998), (2000, 11, 29, 20, 58, 16, 999999), ] t1 = self.theclass(*args) t2 = self.theclass(*args) self.assertEqual(t1, t2) self.assertTrue(t1 <= t2) self.assertTrue(t1 >= t2) self.assertFalse(t1 != t2) self.assertFalse(t1 < t2) self.assertFalse(t1 > t2) for i in range(len(args)): newargs = newargsx[i] t2 = self.theclass(*newargs) # this is larger than t1 self.assertTrue(t1 < t2) self.assertTrue(t2 > t1) self.assertTrue(t1 <= t2) self.assertTrue(t2 >= t1) self.assertTrue(t1 != t2) self.assertTrue(t2 != t1) self.assertFalse(t1 == t2) self.assertFalse(t2 == t1) self.assertFalse(t1 > t2) self.assertFalse(t2 < t1) self.assertFalse(t1 >= t2) self.assertFalse(t2 <= t1) # A helper for timestamp constructor tests. def verify_field_equality(self, expected, got): self.assertEqual(expected.tm_year, got.year) self.assertEqual(expected.tm_mon, got.month) self.assertEqual(expected.tm_mday, got.day) self.assertEqual(expected.tm_hour, got.hour) self.assertEqual(expected.tm_min, got.minute) self.assertEqual(expected.tm_sec, got.second) def test_fromtimestamp(self): import time ts = time.time() expected = time.localtime(int(ts)) got = self.theclass.fromtimestamp(ts) self.verify_field_equality(expected, got) """ def test_utcfromtimestamp(self): import time ts = time.time() expected = time.gmtime(int(ts)) got = self.theclass.utcfromtimestamp(ts) self.verify_field_equality(expected, got) """ def test_timestamp_naive(self): """ t = self.theclass(1970, 1, 1) self.assertEqual(t.timestamp(), 18000.0) t = self.theclass(1970, 1, 1, 1, 2, 3, 4) self.assertEqual(t.timestamp(), 18000.0 + 3600 + 2*60 + 3 + 4*1e-6) """ t = self.theclass(1970, 1, 1) self.assertEqual(t.timestamp(), 0) t = self.theclass(1970, 1, 1, 1, 2, 3, 4) self.assertEqual(t.timestamp(), 3600 + 2 * 60 + 3 + 4 * 1e-6) """ # Missing hour t0 = self.theclass(2012, 3, 11, 2, 30) t1 = t0.replace(fold=1) self.assertEqual(self.theclass.fromtimestamp(t1.timestamp()), t0 - timedelta(hours=1)) self.assertEqual(self.theclass.fromtimestamp(t0.timestamp()), t1 + timedelta(hours=1)) # Ambiguous hour defaults to DST t = self.theclass(2012, 11, 4, 1, 30) self.assertEqual(self.theclass.fromtimestamp(t.timestamp()), t) # Timestamp may raise an overflow error on some platforms # XXX: Do we care to support the first and last year? for t in [self.theclass(2,1,1), self.theclass(9998,12,12)]: s = None try: s = t.timestamp() except OverflowError: continue self.assertEqual(self.theclass.fromtimestamp(s), t) """ """ def test_timestamp_aware(self): t = self.theclass(1970, 1, 1, tzinfo=timezone.utc) self.assertEqual(t.timestamp(), 0.0) t = self.theclass(1970, 1, 1, 1, 2, 3, 4, tzinfo=timezone.utc) self.assertEqual(t.timestamp(), 3600 + 2*60 + 3 + 4*1e-6) t = self.theclass(1970, 1, 1, 1, 2, 3, 4, tzinfo=timezone(timedelta(hours=-5), 'EST')) self.assertEqual(t.timestamp(), 18000 + 3600 + 2*60 + 3 + 4*1e-6) """ """ def test_microsecond_rounding(self): for fts in (self.theclass.fromtimestamp, self.theclass.utcfromtimestamp): zero = fts(0) self.assertEqual(zero.second, 0) self.assertEqual(zero.microsecond, 0) one = fts(1e-6) minus_one = fts(-1e-6) self.assertEqual(minus_one.second, 59) self.assertEqual(minus_one.microsecond, 999999) t = fts(-1e-8) self.assertEqual(t, zero) t = fts(-9e-7) self.assertEqual(t, minus_one) t = fts(-1e-7) self.assertEqual(t, zero) t = fts(-1/2**7) self.assertEqual(t.second, 59) self.assertEqual(t.microsecond, 992188) t = fts(1e-7) self.assertEqual(t, zero) t = fts(9e-7) self.assertEqual(t, one) t = fts(0.99999949) self.assertEqual(t.second, 0) self.assertEqual(t.microsecond, 999999) t = fts(0.9999999) self.assertEqual(t.second, 1) self.assertEqual(t.microsecond, 0) t = fts(1/2**7) self.assertEqual(t.second, 0) self.assertEqual(t.microsecond, 7812) """ """ def test_timestamp_limits(self): # minimum timestamp min_dt = self.theclass.min.replace(tzinfo=timezone.utc) min_ts = min_dt.timestamp() try: # date 0001-01-01 00:00:00+00:00: timestamp=-62135596800 self.assertEqual(self.theclass.fromtimestamp(min_ts, tz=timezone.utc), min_dt) except (OverflowError, OSError) as exc: # the date 0001-01-01 doesn't fit into 32-bit time_t, # or platform doesn't support such very old date self.skipTest(str(exc)) # maximum timestamp: set seconds to zero to avoid rounding issues max_dt = self.theclass.max.replace(tzinfo=timezone.utc, second=0, microsecond=0) max_ts = max_dt.timestamp() # date 9999-12-31 23:59:00+00:00: timestamp 253402300740 self.assertEqual(self.theclass.fromtimestamp(max_ts, tz=timezone.utc), max_dt) # number of seconds greater than 1 year: make sure that the new date # is not valid in datetime.datetime limits delta = 3600 * 24 * 400 # too small ts = min_ts - delta # converting a Python int to C time_t can raise a OverflowError, # especially on 32-bit platforms. self.assertRaises(ValueError, self.theclass.fromtimestamp, ts) self.assertRaises(ValueError, self.theclass.utcfromtimestamp, ts) # too big ts = max_dt.timestamp() + delta self.assertRaises(ValueError, self.theclass.fromtimestamp, ts) self.assertRaises(ValueError, self.theclass.utcfromtimestamp, ts) """ def test_negative_float_fromtimestamp(self): # The result is tz-dependent; at least test that this doesn't # fail (like it did before bug 1646728 was fixed). self.theclass.fromtimestamp(-1.05) """ def test_negative_float_utcfromtimestamp(self): d = self.theclass.utcfromtimestamp(-1.05) self.assertEqual(d, self.theclass(1969, 12, 31, 23, 59, 58, 950000)) """ def test_utcnow(self): import time # Call it a success if utcnow() and utcfromtimestamp() are within # a second of each other. from_timestamp = None from_now = None tolerance = timedelta(seconds=1) for dummy in range(3): from_now = self.theclass.utcnow() from_timestamp = self.theclass.utcfromtimestamp(time.time()) if abs(from_timestamp.__val__() - from_now.__val__()) <= tolerance: break # Else try again a few times. self.assertLessEqual(abs(from_timestamp.__val__() - from_now.__val__()), tolerance) def test_extract(self): dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234) self.assertEqual(dt.date(), date(2002, 3, 4)) self.assertEqual(dt.time(), time(18, 45, 3, 1234)) def test_combine(self): d = date(2002, 3, 4) t = time(18, 45, 3, 1234) expected = self.theclass(2002, 3, 4, 18, 45, 3, 1234) combine = self.theclass.combine dt = combine(d, t) self.assertEqual(dt, expected) dt = combine(time=t, date=d) self.assertEqual(dt, expected) self.assertEqual(d, dt.date()) self.assertEqual(t, dt.time()) self.assertEqual(dt, combine(dt.date(), dt.time())) """ self.assertRaises(TypeError, combine) # need an arg self.assertRaises(TypeError, combine, d) # need two args self.assertRaises(TypeError, combine, t, d) # args reversed self.assertRaises(TypeError, combine, d, t, 1) # wrong tzinfo type self.assertRaises(TypeError, combine, d, t, 1, 2) # too many args self.assertRaises(TypeError, combine, "date", "time") # wrong types self.assertRaises(TypeError, combine, d, "time") # wrong type self.assertRaises(TypeError, combine, "date", t) # wrong type # tzinfo= argument dt = combine(d, t, timezone.utc) self.assertIs(dt.tzinfo, timezone.utc) dt = combine(d, t, tzinfo=timezone.utc) self.assertIs(dt.tzinfo, timezone.utc) t = time() dt = combine(dt, t) self.assertEqual(dt.date(), d) self.assertEqual(dt.time(), t) """ def test_replace(self): cls = self.theclass args = (1, 2, 3, 4, 5, 6, 7) base = cls(*args) self.assertEqual(base, base.replace()) self.assertEqual(base.replace(year=2), cls(2, 2, 3, 4, 5, 6, 7)) self.assertEqual(base.replace(month=3), cls(1, 3, 3, 4, 5, 6, 7)) self.assertEqual(base.replace(day=4), cls(1, 2, 4, 4, 5, 6, 7)) self.assertEqual(base.replace(hour=5), cls(1, 2, 3, 5, 5, 6, 7)) self.assertEqual(base.replace(minute=6), cls(1, 2, 3, 4, 6, 6, 7)) self.assertEqual(base.replace(second=7), cls(1, 2, 3, 4, 5, 7, 7)) self.assertEqual(base.replace(microsecond=8), cls(1, 2, 3, 4, 5, 6, 8)) # Out of bounds. base = cls(2000, 2, 29) self.assertRaises(ValueError, lambda: base.replace(year=2001)) """ def test_astimezone(self): dt = self.theclass.now() f = FixedOffset(44, "0044") dt_utc = dt.replace(tzinfo=timezone(timedelta(hours=-4), 'EDT')) self.assertEqual(dt.astimezone(), dt_utc) # naive self.assertRaises(TypeError, dt.astimezone, f, f) # too many args self.assertRaises(TypeError, dt.astimezone, dt) # arg wrong type dt_f = dt.replace(tzinfo=f) + timedelta(hours=4, minutes=44) self.assertEqual(dt.astimezone(f), dt_f) # naive self.assertEqual(dt.astimezone(tz=f), dt_f) # naive class Bogus(tzinfo): def utcoffset(self, dt): return None def dst(self, dt): return timedelta(0) bog = Bogus() self.assertRaises(ValueError, dt.astimezone, bog) # naive self.assertEqual(dt.replace(tzinfo=bog).astimezone(f), dt_f) class AlsoBogus(tzinfo): def utcoffset(self, dt): return timedelta(0) def dst(self, dt): return None alsobog = AlsoBogus() self.assertRaises(ValueError, dt.astimezone, alsobog) # also naive class Broken(tzinfo): def utcoffset(self, dt): return 1 def dst(self, dt): return 1 broken = Broken() dt_broken = dt.replace(tzinfo=broken) with self.assertRaises(TypeError): dt_broken.astimezone() """ def test_fromisoformat_datetime(self): # Test that isoformat() is reversible base_dates = [(1, 1, 1), (1900, 1, 1), (2004, 11, 12), (2017, 5, 30)] base_times = [ (0, 0, 0, 0), (0, 0, 0, 241000), (0, 0, 0, 234567), (12, 30, 45, 234567), ] separators = [" ", "T"] dts = [ self.theclass(*date_tuple, *time_tuple) for date_tuple in base_dates for time_tuple in base_times ] for dt in dts: for sep in separators: dtstr = dt.isoformat(sep=sep) dt_rt = self.theclass.fromisoformat(dtstr) self.assertEqual(dt, dt_rt) def test_fromisoformat_separators(self): separators = [" ", "T"] for sep in separators: dt = self.theclass(2018, 1, 31, 23, 59, 47, 124789) dtstr = dt.isoformat(sep=sep) dt_rt = self.theclass.fromisoformat(dtstr) self.assertEqual(dt, dt_rt) def test_fromisoformat_ambiguous(self): # Test strings like 2018-01-31+12:15 (where +12:15 is not a time zone) separators = ["+", "-"] for sep in separators: dt = self.theclass(2018, 1, 31, 12, 15) dtstr = dt.isoformat(sep=sep) dt_rt = self.theclass.fromisoformat(dtstr) self.assertEqual(dt, dt_rt) def test_fromisoformat_timespecs(self): datetime_bases = [(2009, 12, 4, 8, 17, 45, 123456), (2009, 12, 4, 8, 17, 45, 0)] timespecs = ["hours", "minutes", "seconds", "milliseconds", "microseconds"] for dt_tuple in datetime_bases: dt = self.theclass(*(dt_tuple[0:4])) dtstr = dt.isoformat(timespec="hours") dt_rt = self.theclass.fromisoformat(dtstr) self.assertEqual(dt, dt_rt) dt = self.theclass(*(dt_tuple[0:5])) dtstr = dt.isoformat(timespec="minutes") dt_rt = self.theclass.fromisoformat(dtstr) self.assertEqual(dt, dt_rt) dt = self.theclass(*(dt_tuple[0:6])) dtstr = dt.isoformat(timespec="seconds") dt_rt = self.theclass.fromisoformat(dtstr) self.assertEqual(dt, dt_rt) new_microseconds = 1000 * (dt_tuple[6] // 1000) dt_tuple2 = (*dt_tuple[0:6], new_microseconds) dt = self.theclass(*(dt_tuple2[0:7])) dtstr = dt.isoformat(timespec="milliseconds") dt_rt = self.theclass.fromisoformat(dtstr) self.assertEqual(dt, dt_rt) dt = self.theclass(*(dt_tuple[0:8])) dtstr = dt.isoformat(timespec="microseconds") dt_rt = self.theclass.fromisoformat(dtstr) self.assertEqual(dt, dt_rt) def test_fromisoformat_fails_datetime(self): # Test that fromisoformat() fails on invalid values bad_strs = [ "", # Empty string "\ud800", # bpo-34454: Surrogate code point "2009.04-19T03", # Wrong first separator "2009-04.19T03", # Wrong second separator "2009-04-19T0a", # Invalid hours "2009-04-19T03:1a:45", # Invalid minutes "2009-04-19T03:15:4a", # Invalid seconds "2009-04-19T03;15:45", # Bad first time separator "2009-04-19T03:15;45", # Bad second time separator "2009-04-19T03:15:4500:00", # Bad time zone separator "2009-04-19T03:15:45.2345", # Too many digits for milliseconds "2009-04-19T03:15:45.1234567", # Too many digits for microseconds "2009-04-19T03:15:45.123456+24:30", # Invalid time zone offset "2009-04-19T03:15:45.123456-24:30", # Invalid negative offset "2009-04-10ᛇᛇᛇᛇᛇ12:15", # Too many unicode separators "2009-04\ud80010T12:15", # Surrogate char in date "2009-04-10T12\ud80015", # Surrogate char in time "2009-04-19T1", # Incomplete hours "2009-04-19T12:3", # Incomplete minutes "2009-04-19T12:30:4", # Incomplete seconds "2009-04-19T12:", # Ends with time separator "2009-04-19T12:30:", # Ends with time separator "2009-04-19T12:30:45.", # Ends with time separator "2009-04-19T12:30:45.123456+", # Ends with timzone separator "2009-04-19T12:30:45.123456-", # Ends with timzone separator "2009-04-19T12:30:45.123456-05:00a", # Extra text "2009-04-19T12:30:45.123-05:00a", # Extra text "2009-04-19T12:30:45-05:00a", # Extra text ] for bad_str in bad_strs: self.assertRaises(ValueError, self.theclass.fromisoformat, bad_str) class TestTime(Static[TestCase]): theclass: type = time def test_basic_attributes(self): t = self.theclass(12, 0) self.assertEqual(t.hour, 12) self.assertEqual(t.minute, 0) self.assertEqual(t.second, 0) self.assertEqual(t.microsecond, 0) def test_basic_attributes_nonzero(self): # Make sure all attributes are non-zero so bugs in # bit-shifting access show up. t = self.theclass(12, 59, 59, 8000) self.assertEqual(t.hour, 12) self.assertEqual(t.minute, 59) self.assertEqual(t.second, 59) self.assertEqual(t.microsecond, 8000) def test_comparing(self): args = (1, 2, 3, 4) newargsx = [(2, 2, 3, 4), (1, 3, 3, 4), (1, 2, 4, 4), (1, 2, 3, 5)] t1 = self.theclass(*args) t2 = self.theclass(*args) self.assertEqual(t1, t2) self.assertTrue(t1 <= t2) self.assertTrue(t1 >= t2) self.assertFalse(t1 != t2) self.assertFalse(t1 < t2) self.assertFalse(t1 > t2) for i in range(len(args)): newargs = newargsx[i] t2 = self.theclass(*newargs) # this is larger than t1 self.assertTrue(t1 < t2) self.assertTrue(t2 > t1) self.assertTrue(t1 <= t2) self.assertTrue(t2 >= t1) self.assertTrue(t1 != t2) self.assertTrue(t2 != t1) self.assertFalse(t1 == t2) self.assertFalse(t2 == t1) self.assertFalse(t1 > t2) self.assertFalse(t2 < t1) self.assertFalse(t1 >= t2) self.assertFalse(t2 <= t1) """ for badarg in OTHERSTUFF: self.assertEqual(t1 == badarg, False) self.assertEqual(t1 != badarg, True) self.assertEqual(badarg == t1, False) self.assertEqual(badarg != t1, True) self.assertRaises(TypeError, lambda: t1 <= badarg) self.assertRaises(TypeError, lambda: t1 < badarg) self.assertRaises(TypeError, lambda: t1 > badarg) self.assertRaises(TypeError, lambda: t1 >= badarg) self.assertRaises(TypeError, lambda: badarg <= t1) self.assertRaises(TypeError, lambda: badarg < t1) self.assertRaises(TypeError, lambda: badarg > t1) self.assertRaises(TypeError, lambda: badarg >= t1) """ def test_bad_constructor_arguments(self): # bad hours self.theclass(0, 0) # no exception self.theclass(23, 0) # no exception make_time1 = lambda a, b: self.theclass(a, b) make_time2 = lambda a, b, c: self.theclass(a, b, c) make_time3 = lambda a, b, c, d: self.theclass(a, b, c, d) self.assertRaises(ValueError, make_time1, -1, 0) self.assertRaises(ValueError, make_time1, 24, 0) # bad minutes self.theclass(23, 0) # no exception self.theclass(23, 59) # no exception self.assertRaises(ValueError, make_time1, 23, -1) self.assertRaises(ValueError, make_time1, 23, 60) # bad seconds self.theclass(23, 59, 0) # no exception self.theclass(23, 59, 59) # no exception self.assertRaises(ValueError, make_time2, 23, 59, -1) self.assertRaises(ValueError, make_time2, 23, 59, 60) # bad microseconds self.theclass(23, 59, 59, 0) # no exception self.theclass(23, 59, 59, 999999) # no exception self.assertRaises(ValueError, make_time3, 23, 59, 59, -1) self.assertRaises(ValueError, make_time3, 23, 59, 59, 1000000) def test_hash_equality(self): d = self.theclass(23, 30, 17) e = self.theclass(23, 30, 17) self.assertEqual(d, e) self.assertEqual(hash(d), hash(e)) dic = {d: 1} dic[e] = 2 self.assertEqual(len(dic), 1) self.assertEqual(dic[d], 2) self.assertEqual(dic[e], 2) d = self.theclass(0, 5, 17) e = self.theclass(0, 5, 17) self.assertEqual(d, e) self.assertEqual(hash(d), hash(e)) dic = {d: 1} dic[e] = 2 self.assertEqual(len(dic), 1) self.assertEqual(dic[d], 2) self.assertEqual(dic[e], 2) def test_isoformat(self): t = self.theclass(4, 5, 1, 123) self.assertEqual(t.isoformat(), "04:05:01.000123") self.assertEqual(t.isoformat(), str(t)) t = self.theclass() self.assertEqual(t.isoformat(), "00:00:00") self.assertEqual(t.isoformat(), str(t)) t = self.theclass(microsecond=1) self.assertEqual(t.isoformat(), "00:00:00.000001") self.assertEqual(t.isoformat(), str(t)) t = self.theclass(microsecond=10) self.assertEqual(t.isoformat(), "00:00:00.000010") self.assertEqual(t.isoformat(), str(t)) t = self.theclass(microsecond=100) self.assertEqual(t.isoformat(), "00:00:00.000100") self.assertEqual(t.isoformat(), str(t)) t = self.theclass(microsecond=1000) self.assertEqual(t.isoformat(), "00:00:00.001000") self.assertEqual(t.isoformat(), str(t)) t = self.theclass(microsecond=10000) self.assertEqual(t.isoformat(), "00:00:00.010000") self.assertEqual(t.isoformat(), str(t)) t = self.theclass(microsecond=100000) self.assertEqual(t.isoformat(), "00:00:00.100000") self.assertEqual(t.isoformat(), str(t)) t = self.theclass(hour=12, minute=34, second=56, microsecond=123456) self.assertEqual(t.isoformat(timespec="hours"), "12") self.assertEqual(t.isoformat(timespec="minutes"), "12:34") self.assertEqual(t.isoformat(timespec="seconds"), "12:34:56") self.assertEqual(t.isoformat(timespec="milliseconds"), "12:34:56.123") self.assertEqual(t.isoformat(timespec="microseconds"), "12:34:56.123456") self.assertEqual(t.isoformat(timespec="auto"), "12:34:56.123456") t = self.theclass(hour=12, minute=34, second=56, microsecond=999500) self.assertEqual(t.isoformat(timespec="milliseconds"), "12:34:56.999") t = self.theclass(hour=12, minute=34, second=56, microsecond=0) self.assertEqual(t.isoformat(timespec="milliseconds"), "12:34:56.000") self.assertEqual(t.isoformat(timespec="microseconds"), "12:34:56.000000") self.assertEqual(t.isoformat(timespec="auto"), "12:34:56") def test_str(self): self.assertEqual(str(self.theclass(1, 2, 3, 4)), "01:02:03.000004") self.assertEqual(str(self.theclass(10, 2, 3, 4000)), "10:02:03.004000") self.assertEqual(str(self.theclass(0, 2, 3, 400000)), "00:02:03.400000") self.assertEqual(str(self.theclass(12, 2, 3, 0)), "12:02:03") self.assertEqual(str(self.theclass(23, 15, 0, 0)), "23:15:00") def test_repr(self): self.assertEqual( repr(self.theclass(1, 2, 3, 4)), "time(hour=1, minute=2, second=3, microsecond=4)", ) self.assertEqual( repr(self.theclass(10, 2, 3, 4000)), "time(hour=10, minute=2, second=3, microsecond=4000)", ) self.assertEqual( repr(self.theclass(0, 2, 3, 400000)), "time(hour=0, minute=2, second=3, microsecond=400000)", ) self.assertEqual( repr(self.theclass(12, 2, 3, 0)), "time(hour=12, minute=2, second=3)" ) self.assertEqual(repr(self.theclass(23, 15, 0, 0)), "time(hour=23, minute=15)") def test_resolution_info(self): self.assertTrue(self.theclass.max > self.theclass.min) def test_bool(self): # time is always True. cls = self.theclass self.assertTrue(cls(1)) self.assertTrue(cls(0, 1)) self.assertTrue(cls(0, 0, 1)) self.assertTrue(cls(0, 0, 0, 1)) self.assertTrue(cls(0)) self.assertTrue(cls()) def test_replace(self): cls = self.theclass args = (1, 2, 3, 4) base = cls(*args) self.assertEqual(base, base.replace()) self.assertEqual(base.replace(hour=5), cls(5, 2, 3, 4)) self.assertEqual(base.replace(minute=6), cls(1, 6, 3, 4)) self.assertEqual(base.replace(second=7), cls(1, 2, 7, 4)) self.assertEqual(base.replace(microsecond=8), cls(1, 2, 3, 8)) # Out of bounds. base = cls(1) self.assertRaises(ValueError, lambda: base.replace(hour=24)) self.assertRaises( ValueError, lambda: base.replace(minute=-2) ) # minute=-1 indicates default; changed to -2 for test self.assertRaises(ValueError, lambda: base.replace(second=100)) self.assertRaises(ValueError, lambda: base.replace(microsecond=1000000)) case_td = TestTimeDelta() case_td.test_computations() case_td.test_constructor() case_td.test_resolution_info() case_td.test_basic_attributes() case_td.test_total_seconds() case_td.test_carries() case_td.test_hash_equality() case_td.test_compare() case_td.test_str() case_td.test_repr() case_td.test_microsecond_rounding() case_td.test_massive_normalization() case_td.test_bool() case_td.test_division() case_td.test_remainder() case_td.test_divmod() case_do = TestDateOnly() case_do.test_delta_non_days_ignored() case_dx = TestDate[date]() case_dx.test_basic_attributes() case_dx.test_ordinal_conversions() # case_dx.test_extreme_ordinals() case_dx.test_bad_constructor_arguments() case_dx.test_hash_equality() case_dx.test_computations() case_dx.test_fromtimestamp() case_dx.test_today() case_dx.test_weekday() case_dx.test_isocalendar() case_dx.test_iso_long_years() case_dx.test_isoformat() case_dx.test_ctime() case_dx.test_timetuple() case_dx.test_compare() case_dx.test_replace() case_dx.test_fromisoformat() case_dx.test_fromisoformat_fails() case_dx.test_fromisocalendar() case_dx.test_fromisocalendar_value_errors() case_dt = TestDateTime[datetime]() case_dt.test_ordinal_conversions() case_dt.test_today() case_dt.test_weekday() case_dt.test_isocalendar() case_dt.test_iso_long_years() case_dt.test_ctime() case_dt.test_timetuple() case_dt.test_compare() case_dt.test_fromisoformat() case_dt.test_fromisoformat_fails() case_dt.test_fromisocalendar_value_errors() # --- case_dt.test_basic_attributes() case_dt.test_basic_attributes_nonzero() case_dt.test_isoformat() # case_dt.test_more_ctime() case_dt.test_tz_independent_comparing() case_dt.test_bad_constructor_arguments() case_dt.test_hash_equality() case_dt.test_computations() case_dt.test_more_compare() case_dt.test_fromtimestamp() # case_dt.test_utcfromtimestamp() case_dt.test_timestamp_naive() # case_dt.test_microsecond_rounding() # case_dt.test_timestamp_limits() case_dt.test_negative_float_fromtimestamp() # case_dt.test_negative_float_utcfromtimestamp() case_dt.test_utcnow() case_dt.test_extract() case_dt.test_combine() case_dt.test_replace() case_dt.test_fromisoformat_datetime() case_dt.test_fromisoformat_separators() case_dt.test_fromisoformat_ambiguous() case_dt.test_fromisoformat_timespecs() case_dt.test_fromisoformat_fails_datetime() case_tx = TestTime() case_tx.test_basic_attributes() case_tx.test_basic_attributes_nonzero() case_tx.test_comparing() case_tx.test_bad_constructor_arguments() case_tx.test_hash_equality() case_tx.test_isoformat() case_tx.test_str() case_tx.test_repr() case_tx.test_resolution_info() case_tx.test_bool() case_tx.test_replace() @test def test_constants(): assert str(timedelta.min) == '-106751992 days, 19:59:05.224192' # note: diff w/ Python assert str(timedelta.max) == '106751991 days, 4:00:54.775807' # note: diff w/ Python assert str(timedelta.resolution) == '0:00:00.000001' assert str(date.min) == '0001-01-01' assert str(date.max) == '9999-12-31' assert str(date.resolution) == '1 day, 0:00:00' assert str(time.min) == '00:00:00' assert str(time.max) == '23:59:59.999999' assert str(time.resolution) == '0:00:00.000001' assert str(datetime.min) == '0001-01-01 00:00:00' assert str(datetime.max) == '9999-12-31 23:59:59.999999' assert str(datetime.resolution) == '0:00:00.000001' test_constants()