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