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