1 from test import support 2 import decimal 3 import enum 4 import locale 5 import math 6 import platform 7 import sys 8 import sysconfig 9 import time 10 import unittest 11 try: 12 import threading 13 except ImportError: 14 threading = None 15 try: 16 import _testcapi 17 except ImportError: 18 _testcapi = None 19 20 21 # Max year is only limited by the size of C int. 22 SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4 23 TIME_MAXYEAR = (1 << 8 * SIZEOF_INT - 1) - 1 24 TIME_MINYEAR = -TIME_MAXYEAR - 1 25 26 SEC_TO_US = 10 ** 6 27 US_TO_NS = 10 ** 3 28 MS_TO_NS = 10 ** 6 29 SEC_TO_NS = 10 ** 9 30 NS_TO_SEC = 10 ** 9 31 32 class _PyTime(enum.IntEnum): 33 # Round towards minus infinity (-inf) 34 ROUND_FLOOR = 0 35 # Round towards infinity (+inf) 36 ROUND_CEILING = 1 37 # Round to nearest with ties going to nearest even integer 38 ROUND_HALF_EVEN = 2 39 40 # Rounding modes supported by PyTime 41 ROUNDING_MODES = ( 42 # (PyTime rounding method, decimal rounding method) 43 (_PyTime.ROUND_FLOOR, decimal.ROUND_FLOOR), 44 (_PyTime.ROUND_CEILING, decimal.ROUND_CEILING), 45 (_PyTime.ROUND_HALF_EVEN, decimal.ROUND_HALF_EVEN), 46 ) 47 48 49 class TimeTestCase(unittest.TestCase): 50 51 def setUp(self): 52 self.t = time.time() 53 54 def test_data_attributes(self): 55 time.altzone 56 time.daylight 57 time.timezone 58 time.tzname 59 60 def test_time(self): 61 time.time() 62 info = time.get_clock_info('time') 63 self.assertFalse(info.monotonic) 64 self.assertTrue(info.adjustable) 65 66 def test_clock(self): 67 time.clock() 68 69 info = time.get_clock_info('clock') 70 self.assertTrue(info.monotonic) 71 self.assertFalse(info.adjustable) 72 73 @unittest.skipUnless(hasattr(time, 'clock_gettime'), 74 'need time.clock_gettime()') 75 def test_clock_realtime(self): 76 time.clock_gettime(time.CLOCK_REALTIME) 77 78 @unittest.skipUnless(hasattr(time, 'clock_gettime'), 79 'need time.clock_gettime()') 80 @unittest.skipUnless(hasattr(time, 'CLOCK_MONOTONIC'), 81 'need time.CLOCK_MONOTONIC') 82 def test_clock_monotonic(self): 83 a = time.clock_gettime(time.CLOCK_MONOTONIC) 84 b = time.clock_gettime(time.CLOCK_MONOTONIC) 85 self.assertLessEqual(a, b) 86 87 @unittest.skipUnless(hasattr(time, 'clock_getres'), 88 'need time.clock_getres()') 89 def test_clock_getres(self): 90 res = time.clock_getres(time.CLOCK_REALTIME) 91 self.assertGreater(res, 0.0) 92 self.assertLessEqual(res, 1.0) 93 94 @unittest.skipUnless(hasattr(time, 'clock_settime'), 95 'need time.clock_settime()') 96 def test_clock_settime(self): 97 t = time.clock_gettime(time.CLOCK_REALTIME) 98 try: 99 time.clock_settime(time.CLOCK_REALTIME, t) 100 except PermissionError: 101 pass 102 103 if hasattr(time, 'CLOCK_MONOTONIC'): 104 self.assertRaises(OSError, 105 time.clock_settime, time.CLOCK_MONOTONIC, 0) 106 107 def test_conversions(self): 108 self.assertEqual(time.ctime(self.t), 109 time.asctime(time.localtime(self.t))) 110 self.assertEqual(int(time.mktime(time.localtime(self.t))), 111 int(self.t)) 112 113 def test_sleep(self): 114 self.assertRaises(ValueError, time.sleep, -2) 115 self.assertRaises(ValueError, time.sleep, -1) 116 time.sleep(1.2) 117 118 def test_strftime(self): 119 tt = time.gmtime(self.t) 120 for directive in ('a', 'A', 'b', 'B', 'c', 'd', 'H', 'I', 121 'j', 'm', 'M', 'p', 'S', 122 'U', 'w', 'W', 'x', 'X', 'y', 'Y', 'Z', '%'): 123 format = ' %' + directive 124 try: 125 time.strftime(format, tt) 126 except ValueError: 127 self.fail('conversion specifier: %r failed.' % format) 128 129 def _bounds_checking(self, func): 130 # Make sure that strftime() checks the bounds of the various parts 131 # of the time tuple (0 is valid for *all* values). 132 133 # The year field is tested by other test cases above 134 135 # Check month [1, 12] + zero support 136 func((1900, 0, 1, 0, 0, 0, 0, 1, -1)) 137 func((1900, 12, 1, 0, 0, 0, 0, 1, -1)) 138 self.assertRaises(ValueError, func, 139 (1900, -1, 1, 0, 0, 0, 0, 1, -1)) 140 self.assertRaises(ValueError, func, 141 (1900, 13, 1, 0, 0, 0, 0, 1, -1)) 142 # Check day of month [1, 31] + zero support 143 func((1900, 1, 0, 0, 0, 0, 0, 1, -1)) 144 func((1900, 1, 31, 0, 0, 0, 0, 1, -1)) 145 self.assertRaises(ValueError, func, 146 (1900, 1, -1, 0, 0, 0, 0, 1, -1)) 147 self.assertRaises(ValueError, func, 148 (1900, 1, 32, 0, 0, 0, 0, 1, -1)) 149 # Check hour [0, 23] 150 func((1900, 1, 1, 23, 0, 0, 0, 1, -1)) 151 self.assertRaises(ValueError, func, 152 (1900, 1, 1, -1, 0, 0, 0, 1, -1)) 153 self.assertRaises(ValueError, func, 154 (1900, 1, 1, 24, 0, 0, 0, 1, -1)) 155 # Check minute [0, 59] 156 func((1900, 1, 1, 0, 59, 0, 0, 1, -1)) 157 self.assertRaises(ValueError, func, 158 (1900, 1, 1, 0, -1, 0, 0, 1, -1)) 159 self.assertRaises(ValueError, func, 160 (1900, 1, 1, 0, 60, 0, 0, 1, -1)) 161 # Check second [0, 61] 162 self.assertRaises(ValueError, func, 163 (1900, 1, 1, 0, 0, -1, 0, 1, -1)) 164 # C99 only requires allowing for one leap second, but Python's docs say 165 # allow two leap seconds (0..61) 166 func((1900, 1, 1, 0, 0, 60, 0, 1, -1)) 167 func((1900, 1, 1, 0, 0, 61, 0, 1, -1)) 168 self.assertRaises(ValueError, func, 169 (1900, 1, 1, 0, 0, 62, 0, 1, -1)) 170 # No check for upper-bound day of week; 171 # value forced into range by a ``% 7`` calculation. 172 # Start check at -2 since gettmarg() increments value before taking 173 # modulo. 174 self.assertEqual(func((1900, 1, 1, 0, 0, 0, -1, 1, -1)), 175 func((1900, 1, 1, 0, 0, 0, +6, 1, -1))) 176 self.assertRaises(ValueError, func, 177 (1900, 1, 1, 0, 0, 0, -2, 1, -1)) 178 # Check day of the year [1, 366] + zero support 179 func((1900, 1, 1, 0, 0, 0, 0, 0, -1)) 180 func((1900, 1, 1, 0, 0, 0, 0, 366, -1)) 181 self.assertRaises(ValueError, func, 182 (1900, 1, 1, 0, 0, 0, 0, -1, -1)) 183 self.assertRaises(ValueError, func, 184 (1900, 1, 1, 0, 0, 0, 0, 367, -1)) 185 186 def test_strftime_bounding_check(self): 187 self._bounds_checking(lambda tup: time.strftime('', tup)) 188 189 def test_strftime_format_check(self): 190 # Test that strftime does not crash on invalid format strings 191 # that may trigger a buffer overread. When not triggered, 192 # strftime may succeed or raise ValueError depending on 193 # the platform. 194 for x in [ '', 'A', '%A', '%AA' ]: 195 for y in range(0x0, 0x10): 196 for z in [ '%', 'A%', 'AA%', '%A%', 'A%A%', '%#' ]: 197 try: 198 time.strftime(x * y + z) 199 except ValueError: 200 pass 201 202 def test_default_values_for_zero(self): 203 # Make sure that using all zeros uses the proper default 204 # values. No test for daylight savings since strftime() does 205 # not change output based on its value and no test for year 206 # because systems vary in their support for year 0. 207 expected = "2000 01 01 00 00 00 1 001" 208 with support.check_warnings(): 209 result = time.strftime("%Y %m %d %H %M %S %w %j", (2000,)+(0,)*8) 210 self.assertEqual(expected, result) 211 212 def test_strptime(self): 213 # Should be able to go round-trip from strftime to strptime without 214 # raising an exception. 215 tt = time.gmtime(self.t) 216 for directive in ('a', 'A', 'b', 'B', 'c', 'd', 'H', 'I', 217 'j', 'm', 'M', 'p', 'S', 218 'U', 'w', 'W', 'x', 'X', 'y', 'Y', 'Z', '%'): 219 format = '%' + directive 220 strf_output = time.strftime(format, tt) 221 try: 222 time.strptime(strf_output, format) 223 except ValueError: 224 self.fail("conversion specifier %r failed with '%s' input." % 225 (format, strf_output)) 226 227 def test_strptime_bytes(self): 228 # Make sure only strings are accepted as arguments to strptime. 229 self.assertRaises(TypeError, time.strptime, b'2009', "%Y") 230 self.assertRaises(TypeError, time.strptime, '2009', b'%Y') 231 232 def test_strptime_exception_context(self): 233 # check that this doesn't chain exceptions needlessly (see #17572) 234 with self.assertRaises(ValueError) as e: 235 time.strptime('', '%D') 236 self.assertIs(e.exception.__suppress_context__, True) 237 # additional check for IndexError branch (issue #19545) 238 with self.assertRaises(ValueError) as e: 239 time.strptime('19', '%Y %') 240 self.assertIs(e.exception.__suppress_context__, True) 241 242 def test_asctime(self): 243 time.asctime(time.gmtime(self.t)) 244 245 # Max year is only limited by the size of C int. 246 for bigyear in TIME_MAXYEAR, TIME_MINYEAR: 247 asc = time.asctime((bigyear, 6, 1) + (0,) * 6) 248 self.assertEqual(asc[-len(str(bigyear)):], str(bigyear)) 249 self.assertRaises(OverflowError, time.asctime, 250 (TIME_MAXYEAR + 1,) + (0,) * 8) 251 self.assertRaises(OverflowError, time.asctime, 252 (TIME_MINYEAR - 1,) + (0,) * 8) 253 self.assertRaises(TypeError, time.asctime, 0) 254 self.assertRaises(TypeError, time.asctime, ()) 255 self.assertRaises(TypeError, time.asctime, (0,) * 10) 256 257 def test_asctime_bounding_check(self): 258 self._bounds_checking(time.asctime) 259 260 def test_ctime(self): 261 t = time.mktime((1973, 9, 16, 1, 3, 52, 0, 0, -1)) 262 self.assertEqual(time.ctime(t), 'Sun Sep 16 01:03:52 1973') 263 t = time.mktime((2000, 1, 1, 0, 0, 0, 0, 0, -1)) 264 self.assertEqual(time.ctime(t), 'Sat Jan 1 00:00:00 2000') 265 for year in [-100, 100, 1000, 2000, 2050, 10000]: 266 try: 267 testval = time.mktime((year, 1, 10) + (0,)*6) 268 except (ValueError, OverflowError): 269 # If mktime fails, ctime will fail too. This may happen 270 # on some platforms. 271 pass 272 else: 273 self.assertEqual(time.ctime(testval)[20:], str(year)) 274 275 @unittest.skipUnless(hasattr(time, "tzset"), 276 "time module has no attribute tzset") 277 def test_tzset(self): 278 279 from os import environ 280 281 # Epoch time of midnight Dec 25th 2002. Never DST in northern 282 # hemisphere. 283 xmas2002 = 1040774400.0 284 285 # These formats are correct for 2002, and possibly future years 286 # This format is the 'standard' as documented at: 287 # http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap08.html 288 # They are also documented in the tzset(3) man page on most Unix 289 # systems. 290 eastern = 'EST+05EDT,M4.1.0,M10.5.0' 291 victoria = 'AEST-10AEDT-11,M10.5.0,M3.5.0' 292 utc='UTC+0' 293 294 org_TZ = environ.get('TZ',None) 295 try: 296 # Make sure we can switch to UTC time and results are correct 297 # Note that unknown timezones default to UTC. 298 # Note that altzone is undefined in UTC, as there is no DST 299 environ['TZ'] = eastern 300 time.tzset() 301 environ['TZ'] = utc 302 time.tzset() 303 self.assertEqual( 304 time.gmtime(xmas2002), time.localtime(xmas2002) 305 ) 306 self.assertEqual(time.daylight, 0) 307 self.assertEqual(time.timezone, 0) 308 self.assertEqual(time.localtime(xmas2002).tm_isdst, 0) 309 310 # Make sure we can switch to US/Eastern 311 environ['TZ'] = eastern 312 time.tzset() 313 self.assertNotEqual(time.gmtime(xmas2002), time.localtime(xmas2002)) 314 self.assertEqual(time.tzname, ('EST', 'EDT')) 315 self.assertEqual(len(time.tzname), 2) 316 self.assertEqual(time.daylight, 1) 317 self.assertEqual(time.timezone, 18000) 318 self.assertEqual(time.altzone, 14400) 319 self.assertEqual(time.localtime(xmas2002).tm_isdst, 0) 320 self.assertEqual(len(time.tzname), 2) 321 322 # Now go to the southern hemisphere. 323 environ['TZ'] = victoria 324 time.tzset() 325 self.assertNotEqual(time.gmtime(xmas2002), time.localtime(xmas2002)) 326 327 # Issue #11886: Australian Eastern Standard Time (UTC+10) is called 328 # "EST" (as Eastern Standard Time, UTC-5) instead of "AEST" 329 # (non-DST timezone), and "EDT" instead of "AEDT" (DST timezone), 330 # on some operating systems (e.g. FreeBSD), which is wrong. See for 331 # example this bug: 332 # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=93810 333 self.assertIn(time.tzname[0], ('AEST' 'EST'), time.tzname[0]) 334 self.assertTrue(time.tzname[1] in ('AEDT', 'EDT'), str(time.tzname[1])) 335 self.assertEqual(len(time.tzname), 2) 336 self.assertEqual(time.daylight, 1) 337 self.assertEqual(time.timezone, -36000) 338 self.assertEqual(time.altzone, -39600) 339 self.assertEqual(time.localtime(xmas2002).tm_isdst, 1) 340 341 finally: 342 # Repair TZ environment variable in case any other tests 343 # rely on it. 344 if org_TZ is not None: 345 environ['TZ'] = org_TZ 346 elif 'TZ' in environ: 347 del environ['TZ'] 348 time.tzset() 349 350 def test_insane_timestamps(self): 351 # It's possible that some platform maps time_t to double, 352 # and that this test will fail there. This test should 353 # exempt such platforms (provided they return reasonable 354 # results!). 355 for func in time.ctime, time.gmtime, time.localtime: 356 for unreasonable in -1e200, 1e200: 357 self.assertRaises(OverflowError, func, unreasonable) 358 359 def test_ctime_without_arg(self): 360 # Not sure how to check the values, since the clock could tick 361 # at any time. Make sure these are at least accepted and 362 # don't raise errors. 363 time.ctime() 364 time.ctime(None) 365 366 def test_gmtime_without_arg(self): 367 gt0 = time.gmtime() 368 gt1 = time.gmtime(None) 369 t0 = time.mktime(gt0) 370 t1 = time.mktime(gt1) 371 self.assertAlmostEqual(t1, t0, delta=0.2) 372 373 def test_localtime_without_arg(self): 374 lt0 = time.localtime() 375 lt1 = time.localtime(None) 376 t0 = time.mktime(lt0) 377 t1 = time.mktime(lt1) 378 self.assertAlmostEqual(t1, t0, delta=0.2) 379 380 def test_mktime(self): 381 # Issue #1726687 382 for t in (-2, -1, 0, 1): 383 if sys.platform.startswith('aix') and t == -1: 384 # Issue #11188, #19748: mktime() returns -1 on error. On Linux, 385 # the tm_wday field is used as a sentinel () to detect if -1 is 386 # really an error or a valid timestamp. On AIX, tm_wday is 387 # unchanged even on success and so cannot be used as a 388 # sentinel. 389 continue 390 try: 391 tt = time.localtime(t) 392 except (OverflowError, OSError): 393 pass 394 else: 395 self.assertEqual(time.mktime(tt), t) 396 397 # Issue #13309: passing extreme values to mktime() or localtime() 398 # borks the glibc's internal timezone data. 399 @unittest.skipUnless(platform.libc_ver()[0] != 'glibc', 400 "disabled because of a bug in glibc. Issue #13309") 401 def test_mktime_error(self): 402 # It may not be possible to reliably make mktime return error 403 # on all platfom. This will make sure that no other exception 404 # than OverflowError is raised for an extreme value. 405 tt = time.gmtime(self.t) 406 tzname = time.strftime('%Z', tt) 407 self.assertNotEqual(tzname, 'LMT') 408 try: 409 time.mktime((-1, 1, 1, 0, 0, 0, -1, -1, -1)) 410 except OverflowError: 411 pass 412 self.assertEqual(time.strftime('%Z', tt), tzname) 413 414 @unittest.skipUnless(hasattr(time, 'monotonic'), 415 'need time.monotonic') 416 def test_monotonic(self): 417 # monotonic() should not go backward 418 times = [time.monotonic() for n in range(100)] 419 t1 = times[0] 420 for t2 in times[1:]: 421 self.assertGreaterEqual(t2, t1, "times=%s" % times) 422 t1 = t2 423 424 # monotonic() includes time elapsed during a sleep 425 t1 = time.monotonic() 426 time.sleep(0.5) 427 t2 = time.monotonic() 428 dt = t2 - t1 429 self.assertGreater(t2, t1) 430 # Issue #20101: On some Windows machines, dt may be slightly low 431 self.assertTrue(0.45 <= dt <= 1.0, dt) 432 433 # monotonic() is a monotonic but non adjustable clock 434 info = time.get_clock_info('monotonic') 435 self.assertTrue(info.monotonic) 436 self.assertFalse(info.adjustable) 437 438 def test_perf_counter(self): 439 time.perf_counter() 440 441 def test_process_time(self): 442 # process_time() should not include time spend during a sleep 443 start = time.process_time() 444 time.sleep(0.100) 445 stop = time.process_time() 446 # use 20 ms because process_time() has usually a resolution of 15 ms 447 # on Windows 448 self.assertLess(stop - start, 0.020) 449 450 info = time.get_clock_info('process_time') 451 self.assertTrue(info.monotonic) 452 self.assertFalse(info.adjustable) 453 454 @unittest.skipUnless(hasattr(time, 'monotonic'), 455 'need time.monotonic') 456 @unittest.skipUnless(hasattr(time, 'clock_settime'), 457 'need time.clock_settime') 458 def test_monotonic_settime(self): 459 t1 = time.monotonic() 460 realtime = time.clock_gettime(time.CLOCK_REALTIME) 461 # jump backward with an offset of 1 hour 462 try: 463 time.clock_settime(time.CLOCK_REALTIME, realtime - 3600) 464 except PermissionError as err: 465 self.skipTest(err) 466 t2 = time.monotonic() 467 time.clock_settime(time.CLOCK_REALTIME, realtime) 468 # monotonic must not be affected by system clock updates 469 self.assertGreaterEqual(t2, t1) 470 471 def test_localtime_failure(self): 472 # Issue #13847: check for localtime() failure 473 invalid_time_t = None 474 for time_t in (-1, 2**30, 2**33, 2**60): 475 try: 476 time.localtime(time_t) 477 except OverflowError: 478 self.skipTest("need 64-bit time_t") 479 except OSError: 480 invalid_time_t = time_t 481 break 482 if invalid_time_t is None: 483 self.skipTest("unable to find an invalid time_t value") 484 485 self.assertRaises(OSError, time.localtime, invalid_time_t) 486 self.assertRaises(OSError, time.ctime, invalid_time_t) 487 488 def test_get_clock_info(self): 489 clocks = ['clock', 'perf_counter', 'process_time', 'time'] 490 if hasattr(time, 'monotonic'): 491 clocks.append('monotonic') 492 493 for name in clocks: 494 info = time.get_clock_info(name) 495 #self.assertIsInstance(info, dict) 496 self.assertIsInstance(info.implementation, str) 497 self.assertNotEqual(info.implementation, '') 498 self.assertIsInstance(info.monotonic, bool) 499 self.assertIsInstance(info.resolution, float) 500 # 0.0 < resolution <= 1.0 501 self.assertGreater(info.resolution, 0.0) 502 self.assertLessEqual(info.resolution, 1.0) 503 self.assertIsInstance(info.adjustable, bool) 504 505 self.assertRaises(ValueError, time.get_clock_info, 'xxx') 506 507 508 class TestLocale(unittest.TestCase): 509 def setUp(self): 510 self.oldloc = locale.setlocale(locale.LC_ALL) 511 512 def tearDown(self): 513 locale.setlocale(locale.LC_ALL, self.oldloc) 514 515 def test_bug_3061(self): 516 try: 517 tmp = locale.setlocale(locale.LC_ALL, "fr_FR") 518 except locale.Error: 519 self.skipTest('could not set locale.LC_ALL to fr_FR') 520 # This should not cause an exception 521 time.strftime("%B", (2009,2,1,0,0,0,0,0,0)) 522 523 524 class _TestAsctimeYear: 525 _format = '%d' 526 527 def yearstr(self, y): 528 return time.asctime((y,) + (0,) * 8).split()[-1] 529 530 def test_large_year(self): 531 # Check that it doesn't crash for year > 9999 532 self.assertEqual(self.yearstr(12345), '12345') 533 self.assertEqual(self.yearstr(123456789), '123456789') 534 535 class _TestStrftimeYear: 536 537 # Issue 13305: For years < 1000, the value is not always 538 # padded to 4 digits across platforms. The C standard 539 # assumes year >= 1900, so it does not specify the number 540 # of digits. 541 542 if time.strftime('%Y', (1,) + (0,) * 8) == '0001': 543 _format = '%04d' 544 else: 545 _format = '%d' 546 547 def yearstr(self, y): 548 return time.strftime('%Y', (y,) + (0,) * 8) 549 550 def test_4dyear(self): 551 # Check that we can return the zero padded value. 552 if self._format == '%04d': 553 self.test_year('%04d') 554 else: 555 def year4d(y): 556 return time.strftime('%4Y', (y,) + (0,) * 8) 557 self.test_year('%04d', func=year4d) 558 559 def skip_if_not_supported(y): 560 msg = "strftime() is limited to [1; 9999] with Visual Studio" 561 # Check that it doesn't crash for year > 9999 562 try: 563 time.strftime('%Y', (y,) + (0,) * 8) 564 except ValueError: 565 cond = False 566 else: 567 cond = True 568 return unittest.skipUnless(cond, msg) 569 570 @skip_if_not_supported(10000) 571 def test_large_year(self): 572 return super().test_large_year() 573 574 @skip_if_not_supported(0) 575 def test_negative(self): 576 return super().test_negative() 577 578 del skip_if_not_supported 579 580 581 class _Test4dYear: 582 _format = '%d' 583 584 def test_year(self, fmt=None, func=None): 585 fmt = fmt or self._format 586 func = func or self.yearstr 587 self.assertEqual(func(1), fmt % 1) 588 self.assertEqual(func(68), fmt % 68) 589 self.assertEqual(func(69), fmt % 69) 590 self.assertEqual(func(99), fmt % 99) 591 self.assertEqual(func(999), fmt % 999) 592 self.assertEqual(func(9999), fmt % 9999) 593 594 def test_large_year(self): 595 self.assertEqual(self.yearstr(12345), '12345') 596 self.assertEqual(self.yearstr(123456789), '123456789') 597 self.assertEqual(self.yearstr(TIME_MAXYEAR), str(TIME_MAXYEAR)) 598 self.assertRaises(OverflowError, self.yearstr, TIME_MAXYEAR + 1) 599 600 def test_negative(self): 601 self.assertEqual(self.yearstr(-1), self._format % -1) 602 self.assertEqual(self.yearstr(-1234), '-1234') 603 self.assertEqual(self.yearstr(-123456), '-123456') 604 self.assertEqual(self.yearstr(-123456789), str(-123456789)) 605 self.assertEqual(self.yearstr(-1234567890), str(-1234567890)) 606 self.assertEqual(self.yearstr(TIME_MINYEAR + 1900), str(TIME_MINYEAR + 1900)) 607 # Issue #13312: it may return wrong value for year < TIME_MINYEAR + 1900 608 # Skip the value test, but check that no error is raised 609 self.yearstr(TIME_MINYEAR) 610 # self.assertEqual(self.yearstr(TIME_MINYEAR), str(TIME_MINYEAR)) 611 self.assertRaises(OverflowError, self.yearstr, TIME_MINYEAR - 1) 612 613 614 class TestAsctime4dyear(_TestAsctimeYear, _Test4dYear, unittest.TestCase): 615 pass 616 617 class TestStrftime4dyear(_TestStrftimeYear, _Test4dYear, unittest.TestCase): 618 pass 619 620 621 class TestPytime(unittest.TestCase): 622 @unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support") 623 def test_localtime_timezone(self): 624 625 # Get the localtime and examine it for the offset and zone. 626 lt = time.localtime() 627 self.assertTrue(hasattr(lt, "tm_gmtoff")) 628 self.assertTrue(hasattr(lt, "tm_zone")) 629 630 # See if the offset and zone are similar to the module 631 # attributes. 632 if lt.tm_gmtoff is None: 633 self.assertTrue(not hasattr(time, "timezone")) 634 else: 635 self.assertEqual(lt.tm_gmtoff, -[time.timezone, time.altzone][lt.tm_isdst]) 636 if lt.tm_zone is None: 637 self.assertTrue(not hasattr(time, "tzname")) 638 else: 639 self.assertEqual(lt.tm_zone, time.tzname[lt.tm_isdst]) 640 641 # Try and make UNIX times from the localtime and a 9-tuple 642 # created from the localtime. Test to see that the times are 643 # the same. 644 t = time.mktime(lt); t9 = time.mktime(lt[:9]) 645 self.assertEqual(t, t9) 646 647 # Make localtimes from the UNIX times and compare them to 648 # the original localtime, thus making a round trip. 649 new_lt = time.localtime(t); new_lt9 = time.localtime(t9) 650 self.assertEqual(new_lt, lt) 651 self.assertEqual(new_lt.tm_gmtoff, lt.tm_gmtoff) 652 self.assertEqual(new_lt.tm_zone, lt.tm_zone) 653 self.assertEqual(new_lt9, lt) 654 self.assertEqual(new_lt.tm_gmtoff, lt.tm_gmtoff) 655 self.assertEqual(new_lt9.tm_zone, lt.tm_zone) 656 657 @unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support") 658 def test_strptime_timezone(self): 659 t = time.strptime("UTC", "%Z") 660 self.assertEqual(t.tm_zone, 'UTC') 661 t = time.strptime("+0500", "%z") 662 self.assertEqual(t.tm_gmtoff, 5 * 3600) 663 664 @unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support") 665 def test_short_times(self): 666 667 import pickle 668 669 # Load a short time structure using pickle. 670 st = b"ctime\nstruct_time\np0\n((I2007\nI8\nI11\nI1\nI24\nI49\nI5\nI223\nI1\ntp1\n(dp2\ntp3\nRp4\n." 671 lt = pickle.loads(st) 672 self.assertIs(lt.tm_gmtoff, None) 673 self.assertIs(lt.tm_zone, None) 674 675 676 @unittest.skipIf(_testcapi is None, 'need the _testcapi module') 677 class CPyTimeTestCase: 678 """ 679 Base class to test the C _PyTime_t API. 680 """ 681 OVERFLOW_SECONDS = None 682 683 def setUp(self): 684 from _testcapi import SIZEOF_TIME_T 685 bits = SIZEOF_TIME_T * 8 - 1 686 self.time_t_min = -2 ** bits 687 self.time_t_max = 2 ** bits - 1 688 689 def time_t_filter(self, seconds): 690 return (self.time_t_min <= seconds <= self.time_t_max) 691 692 def _rounding_values(self, use_float): 693 "Build timestamps used to test rounding." 694 695 units = [1, US_TO_NS, MS_TO_NS, SEC_TO_NS] 696 if use_float: 697 # picoseconds are only tested to pytime_converter accepting floats 698 units.append(1e-3) 699 700 values = ( 701 # small values 702 1, 2, 5, 7, 123, 456, 1234, 703 # 10^k - 1 704 9, 705 99, 706 999, 707 9999, 708 99999, 709 999999, 710 # test half even rounding near 0.5, 1.5, 2.5, 3.5, 4.5 711 499, 500, 501, 712 1499, 1500, 1501, 713 2500, 714 3500, 715 4500, 716 ) 717 718 ns_timestamps = [0] 719 for unit in units: 720 for value in values: 721 ns = value * unit 722 ns_timestamps.extend((-ns, ns)) 723 for pow2 in (0, 5, 10, 15, 22, 23, 24, 30, 33): 724 ns = (2 ** pow2) * SEC_TO_NS 725 ns_timestamps.extend(( 726 -ns-1, -ns, -ns+1, 727 ns-1, ns, ns+1 728 )) 729 for seconds in (_testcapi.INT_MIN, _testcapi.INT_MAX): 730 ns_timestamps.append(seconds * SEC_TO_NS) 731 if use_float: 732 # numbers with an exact representation in IEEE 754 (base 2) 733 for pow2 in (3, 7, 10, 15): 734 ns = 2.0 ** (-pow2) 735 ns_timestamps.extend((-ns, ns)) 736 737 # seconds close to _PyTime_t type limit 738 ns = (2 ** 63 // SEC_TO_NS) * SEC_TO_NS 739 ns_timestamps.extend((-ns, ns)) 740 741 return ns_timestamps 742 743 def _check_rounding(self, pytime_converter, expected_func, 744 use_float, unit_to_sec, value_filter=None): 745 746 def convert_values(ns_timestamps): 747 if use_float: 748 unit_to_ns = SEC_TO_NS / float(unit_to_sec) 749 values = [ns / unit_to_ns for ns in ns_timestamps] 750 else: 751 unit_to_ns = SEC_TO_NS // unit_to_sec 752 values = [ns // unit_to_ns for ns in ns_timestamps] 753 754 if value_filter: 755 values = filter(value_filter, values) 756 757 # remove duplicates and sort 758 return sorted(set(values)) 759 760 # test rounding 761 ns_timestamps = self._rounding_values(use_float) 762 valid_values = convert_values(ns_timestamps) 763 for time_rnd, decimal_rnd in ROUNDING_MODES : 764 context = decimal.getcontext() 765 context.rounding = decimal_rnd 766 767 for value in valid_values: 768 debug_info = {'value': value, 'rounding': decimal_rnd} 769 try: 770 result = pytime_converter(value, time_rnd) 771 expected = expected_func(value) 772 except Exception as exc: 773 self.fail("Error on timestamp conversion: %s" % debug_info) 774 self.assertEqual(result, 775 expected, 776 debug_info) 777 778 # test overflow 779 ns = self.OVERFLOW_SECONDS * SEC_TO_NS 780 ns_timestamps = (-ns, ns) 781 overflow_values = convert_values(ns_timestamps) 782 for time_rnd, _ in ROUNDING_MODES : 783 for value in overflow_values: 784 debug_info = {'value': value, 'rounding': time_rnd} 785 with self.assertRaises(OverflowError, msg=debug_info): 786 pytime_converter(value, time_rnd) 787 788 def check_int_rounding(self, pytime_converter, expected_func, 789 unit_to_sec=1, value_filter=None): 790 self._check_rounding(pytime_converter, expected_func, 791 False, unit_to_sec, value_filter) 792 793 def check_float_rounding(self, pytime_converter, expected_func, 794 unit_to_sec=1, value_filter=None): 795 self._check_rounding(pytime_converter, expected_func, 796 True, unit_to_sec, value_filter) 797 798 def decimal_round(self, x): 799 d = decimal.Decimal(x) 800 d = d.quantize(1) 801 return int(d) 802 803 804 class TestCPyTime(CPyTimeTestCase, unittest.TestCase): 805 """ 806 Test the C _PyTime_t API. 807 """ 808 # _PyTime_t is a 64-bit signed integer 809 OVERFLOW_SECONDS = math.ceil((2**63 + 1) / SEC_TO_NS) 810 811 def test_FromSeconds(self): 812 from _testcapi import PyTime_FromSeconds 813 814 # PyTime_FromSeconds() expects a C int, reject values out of range 815 def c_int_filter(secs): 816 return (_testcapi.INT_MIN <= secs <= _testcapi.INT_MAX) 817 818 self.check_int_rounding(lambda secs, rnd: PyTime_FromSeconds(secs), 819 lambda secs: secs * SEC_TO_NS, 820 value_filter=c_int_filter) 821 822 def test_FromSecondsObject(self): 823 from _testcapi import PyTime_FromSecondsObject 824 825 self.check_int_rounding( 826 PyTime_FromSecondsObject, 827 lambda secs: secs * SEC_TO_NS) 828 829 self.check_float_rounding( 830 PyTime_FromSecondsObject, 831 lambda ns: self.decimal_round(ns * SEC_TO_NS)) 832 833 def test_AsSecondsDouble(self): 834 from _testcapi import PyTime_AsSecondsDouble 835 836 def float_converter(ns): 837 if abs(ns) % SEC_TO_NS == 0: 838 return float(ns // SEC_TO_NS) 839 else: 840 return float(ns) / SEC_TO_NS 841 842 self.check_int_rounding(lambda ns, rnd: PyTime_AsSecondsDouble(ns), 843 float_converter, 844 NS_TO_SEC) 845 846 def create_decimal_converter(self, denominator): 847 denom = decimal.Decimal(denominator) 848 849 def converter(value): 850 d = decimal.Decimal(value) / denom 851 return self.decimal_round(d) 852 853 return converter 854 855 def test_AsTimeval(self): 856 from _testcapi import PyTime_AsTimeval 857 858 us_converter = self.create_decimal_converter(US_TO_NS) 859 860 def timeval_converter(ns): 861 us = us_converter(ns) 862 return divmod(us, SEC_TO_US) 863 864 if sys.platform == 'win32': 865 from _testcapi import LONG_MIN, LONG_MAX 866 867 # On Windows, timeval.tv_sec type is a C long 868 def seconds_filter(secs): 869 return LONG_MIN <= secs <= LONG_MAX 870 else: 871 seconds_filter = self.time_t_filter 872 873 self.check_int_rounding(PyTime_AsTimeval, 874 timeval_converter, 875 NS_TO_SEC, 876 value_filter=seconds_filter) 877 878 @unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec'), 879 'need _testcapi.PyTime_AsTimespec') 880 def test_AsTimespec(self): 881 from _testcapi import PyTime_AsTimespec 882 883 def timespec_converter(ns): 884 return divmod(ns, SEC_TO_NS) 885 886 self.check_int_rounding(lambda ns, rnd: PyTime_AsTimespec(ns), 887 timespec_converter, 888 NS_TO_SEC, 889 value_filter=self.time_t_filter) 890 891 def test_AsMilliseconds(self): 892 from _testcapi import PyTime_AsMilliseconds 893 894 self.check_int_rounding(PyTime_AsMilliseconds, 895 self.create_decimal_converter(MS_TO_NS), 896 NS_TO_SEC) 897 898 def test_AsMicroseconds(self): 899 from _testcapi import PyTime_AsMicroseconds 900 901 self.check_int_rounding(PyTime_AsMicroseconds, 902 self.create_decimal_converter(US_TO_NS), 903 NS_TO_SEC) 904 905 906 class TestOldPyTime(CPyTimeTestCase, unittest.TestCase): 907 """ 908 Test the old C _PyTime_t API: _PyTime_ObjectToXXX() functions. 909 """ 910 911 # time_t is a 32-bit or 64-bit signed integer 912 OVERFLOW_SECONDS = 2 ** 64 913 914 def test_object_to_time_t(self): 915 from _testcapi import pytime_object_to_time_t 916 917 self.check_int_rounding(pytime_object_to_time_t, 918 lambda secs: secs, 919 value_filter=self.time_t_filter) 920 921 self.check_float_rounding(pytime_object_to_time_t, 922 self.decimal_round, 923 value_filter=self.time_t_filter) 924 925 def create_converter(self, sec_to_unit): 926 def converter(secs): 927 floatpart, intpart = math.modf(secs) 928 intpart = int(intpart) 929 floatpart *= sec_to_unit 930 floatpart = self.decimal_round(floatpart) 931 if floatpart < 0: 932 floatpart += sec_to_unit 933 intpart -= 1 934 elif floatpart >= sec_to_unit: 935 floatpart -= sec_to_unit 936 intpart += 1 937 return (intpart, floatpart) 938 return converter 939 940 def test_object_to_timeval(self): 941 from _testcapi import pytime_object_to_timeval 942 943 self.check_int_rounding(pytime_object_to_timeval, 944 lambda secs: (secs, 0), 945 value_filter=self.time_t_filter) 946 947 self.check_float_rounding(pytime_object_to_timeval, 948 self.create_converter(SEC_TO_US), 949 value_filter=self.time_t_filter) 950 951 def test_object_to_timespec(self): 952 from _testcapi import pytime_object_to_timespec 953 954 self.check_int_rounding(pytime_object_to_timespec, 955 lambda secs: (secs, 0), 956 value_filter=self.time_t_filter) 957 958 self.check_float_rounding(pytime_object_to_timespec, 959 self.create_converter(SEC_TO_NS), 960 value_filter=self.time_t_filter) 961 962 963 if __name__ == "__main__": 964 unittest.main() 965