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