1 from test import support 2 import decimal 3 import enum 4 import locale 5 import math 6 import platform 7 import sys 8 import sysconfig 9 import time 10 import threading 11 import unittest 12 import warnings 13 try: 14 import _testcapi 15 except ImportError: 16 _testcapi = None 17 18 19 # Max year is only limited by the size of C int. 20 SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4 21 TIME_MAXYEAR = (1 << 8 * SIZEOF_INT - 1) - 1 22 TIME_MINYEAR = -TIME_MAXYEAR - 1 + 1900 23 24 SEC_TO_US = 10 ** 6 25 US_TO_NS = 10 ** 3 26 MS_TO_NS = 10 ** 6 27 SEC_TO_NS = 10 ** 9 28 NS_TO_SEC = 10 ** 9 29 30 class _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 41 ROUNDING_MODES = ( 42 # (PyTime rounding method, decimal rounding method) 43 (_PyTime.ROUND_FLOOR, decimal.ROUND_FLOOR), 44 (_PyTime.ROUND_CEILING, decimal.ROUND_CEILING), 45 (_PyTime.ROUND_HALF_EVEN, decimal.ROUND_HALF_EVEN), 46 (_PyTime.ROUND_UP, decimal.ROUND_UP), 47 ) 48 49 50 class 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 def test_clock(self): 93 with self.assertWarns(DeprecationWarning): 94 time.clock() 95 96 with self.assertWarns(DeprecationWarning): 97 info = time.get_clock_info('clock') 98 self.assertTrue(info.monotonic) 99 self.assertFalse(info.adjustable) 100 101 @unittest.skipUnless(hasattr(time, 'clock_gettime'), 102 'need time.clock_gettime()') 103 def test_clock_realtime(self): 104 t = time.clock_gettime(time.CLOCK_REALTIME) 105 self.assertIsInstance(t, float) 106 107 @unittest.skipUnless(hasattr(time, 'clock_gettime'), 108 'need time.clock_gettime()') 109 @unittest.skipUnless(hasattr(time, 'CLOCK_MONOTONIC'), 110 'need time.CLOCK_MONOTONIC') 111 def test_clock_monotonic(self): 112 a = time.clock_gettime(time.CLOCK_MONOTONIC) 113 b = time.clock_gettime(time.CLOCK_MONOTONIC) 114 self.assertLessEqual(a, b) 115 116 @unittest.skipUnless(hasattr(time, 'pthread_getcpuclockid'), 117 'need time.pthread_getcpuclockid()') 118 @unittest.skipUnless(hasattr(time, 'clock_gettime'), 119 'need time.clock_gettime()') 120 def test_pthread_getcpuclockid(self): 121 clk_id = time.pthread_getcpuclockid(threading.get_ident()) 122 self.assertTrue(type(clk_id) is int) 123 self.assertNotEqual(clk_id, time.CLOCK_THREAD_CPUTIME_ID) 124 t1 = time.clock_gettime(clk_id) 125 t2 = time.clock_gettime(clk_id) 126 self.assertLessEqual(t1, t2) 127 128 @unittest.skipUnless(hasattr(time, 'clock_getres'), 129 'need time.clock_getres()') 130 def test_clock_getres(self): 131 res = time.clock_getres(time.CLOCK_REALTIME) 132 self.assertGreater(res, 0.0) 133 self.assertLessEqual(res, 1.0) 134 135 @unittest.skipUnless(hasattr(time, 'clock_settime'), 136 'need time.clock_settime()') 137 def test_clock_settime(self): 138 t = time.clock_gettime(time.CLOCK_REALTIME) 139 try: 140 time.clock_settime(time.CLOCK_REALTIME, t) 141 except PermissionError: 142 pass 143 144 if hasattr(time, 'CLOCK_MONOTONIC'): 145 self.assertRaises(OSError, 146 time.clock_settime, time.CLOCK_MONOTONIC, 0) 147 148 def test_conversions(self): 149 self.assertEqual(time.ctime(self.t), 150 time.asctime(time.localtime(self.t))) 151 self.assertEqual(int(time.mktime(time.localtime(self.t))), 152 int(self.t)) 153 154 def test_sleep(self): 155 self.assertRaises(ValueError, time.sleep, -2) 156 self.assertRaises(ValueError, time.sleep, -1) 157 time.sleep(1.2) 158 159 def test_strftime(self): 160 tt = time.gmtime(self.t) 161 for directive in ('a', 'A', 'b', 'B', 'c', 'd', 'H', 'I', 162 'j', 'm', 'M', 'p', 'S', 163 'U', 'w', 'W', 'x', 'X', 'y', 'Y', 'Z', '%'): 164 format = ' %' + directive 165 try: 166 time.strftime(format, tt) 167 except ValueError: 168 self.fail('conversion specifier: %r failed.' % format) 169 170 self.assertRaises(TypeError, time.strftime, b'%S', tt) 171 # embedded null character 172 self.assertRaises(ValueError, time.strftime, '%S\0', tt) 173 174 def _bounds_checking(self, func): 175 # Make sure that strftime() checks the bounds of the various parts 176 # of the time tuple (0 is valid for *all* values). 177 178 # The year field is tested by other test cases above 179 180 # Check month [1, 12] + zero support 181 func((1900, 0, 1, 0, 0, 0, 0, 1, -1)) 182 func((1900, 12, 1, 0, 0, 0, 0, 1, -1)) 183 self.assertRaises(ValueError, func, 184 (1900, -1, 1, 0, 0, 0, 0, 1, -1)) 185 self.assertRaises(ValueError, func, 186 (1900, 13, 1, 0, 0, 0, 0, 1, -1)) 187 # Check day of month [1, 31] + zero support 188 func((1900, 1, 0, 0, 0, 0, 0, 1, -1)) 189 func((1900, 1, 31, 0, 0, 0, 0, 1, -1)) 190 self.assertRaises(ValueError, func, 191 (1900, 1, -1, 0, 0, 0, 0, 1, -1)) 192 self.assertRaises(ValueError, func, 193 (1900, 1, 32, 0, 0, 0, 0, 1, -1)) 194 # Check hour [0, 23] 195 func((1900, 1, 1, 23, 0, 0, 0, 1, -1)) 196 self.assertRaises(ValueError, func, 197 (1900, 1, 1, -1, 0, 0, 0, 1, -1)) 198 self.assertRaises(ValueError, func, 199 (1900, 1, 1, 24, 0, 0, 0, 1, -1)) 200 # Check minute [0, 59] 201 func((1900, 1, 1, 0, 59, 0, 0, 1, -1)) 202 self.assertRaises(ValueError, func, 203 (1900, 1, 1, 0, -1, 0, 0, 1, -1)) 204 self.assertRaises(ValueError, func, 205 (1900, 1, 1, 0, 60, 0, 0, 1, -1)) 206 # Check second [0, 61] 207 self.assertRaises(ValueError, func, 208 (1900, 1, 1, 0, 0, -1, 0, 1, -1)) 209 # C99 only requires allowing for one leap second, but Python's docs say 210 # allow two leap seconds (0..61) 211 func((1900, 1, 1, 0, 0, 60, 0, 1, -1)) 212 func((1900, 1, 1, 0, 0, 61, 0, 1, -1)) 213 self.assertRaises(ValueError, func, 214 (1900, 1, 1, 0, 0, 62, 0, 1, -1)) 215 # No check for upper-bound day of week; 216 # value forced into range by a ``% 7`` calculation. 217 # Start check at -2 since gettmarg() increments value before taking 218 # modulo. 219 self.assertEqual(func((1900, 1, 1, 0, 0, 0, -1, 1, -1)), 220 func((1900, 1, 1, 0, 0, 0, +6, 1, -1))) 221 self.assertRaises(ValueError, func, 222 (1900, 1, 1, 0, 0, 0, -2, 1, -1)) 223 # Check day of the year [1, 366] + zero support 224 func((1900, 1, 1, 0, 0, 0, 0, 0, -1)) 225 func((1900, 1, 1, 0, 0, 0, 0, 366, -1)) 226 self.assertRaises(ValueError, func, 227 (1900, 1, 1, 0, 0, 0, 0, -1, -1)) 228 self.assertRaises(ValueError, func, 229 (1900, 1, 1, 0, 0, 0, 0, 367, -1)) 230 231 def test_strftime_bounding_check(self): 232 self._bounds_checking(lambda tup: time.strftime('', tup)) 233 234 def test_strftime_format_check(self): 235 # Test that strftime does not crash on invalid format strings 236 # that may trigger a buffer overread. When not triggered, 237 # strftime may succeed or raise ValueError depending on 238 # the platform. 239 for x in [ '', 'A', '%A', '%AA' ]: 240 for y in range(0x0, 0x10): 241 for z in [ '%', 'A%', 'AA%', '%A%', 'A%A%', '%#' ]: 242 try: 243 time.strftime(x * y + z) 244 except ValueError: 245 pass 246 247 def test_default_values_for_zero(self): 248 # Make sure that using all zeros uses the proper default 249 # values. No test for daylight savings since strftime() does 250 # not change output based on its value and no test for year 251 # because systems vary in their support for year 0. 252 expected = "2000 01 01 00 00 00 1 001" 253 with support.check_warnings(): 254 result = time.strftime("%Y %m %d %H %M %S %w %j", (2000,)+(0,)*8) 255 self.assertEqual(expected, result) 256 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 if sys.platform.startswith('aix') and t == -1: 429 # Issue #11188, #19748: mktime() returns -1 on error. On Linux, 430 # the tm_wday field is used as a sentinel () to detect if -1 is 431 # really an error or a valid timestamp. On AIX, tm_wday is 432 # unchanged even on success and so cannot be used as a 433 # sentinel. 434 continue 435 try: 436 tt = time.localtime(t) 437 except (OverflowError, OSError): 438 pass 439 else: 440 self.assertEqual(time.mktime(tt), t) 441 442 # Issue #13309: passing extreme values to mktime() or localtime() 443 # borks the glibc's internal timezone data. 444 @unittest.skipUnless(platform.libc_ver()[0] != 'glibc', 445 "disabled because of a bug in glibc. Issue #13309") 446 def test_mktime_error(self): 447 # It may not be possible to reliably make mktime return error 448 # on all platfom. This will make sure that no other exception 449 # than OverflowError is raised for an extreme value. 450 tt = time.gmtime(self.t) 451 tzname = time.strftime('%Z', tt) 452 self.assertNotEqual(tzname, 'LMT') 453 try: 454 time.mktime((-1, 1, 1, 0, 0, 0, -1, -1, -1)) 455 except OverflowError: 456 pass 457 self.assertEqual(time.strftime('%Z', tt), tzname) 458 459 def test_monotonic(self): 460 # monotonic() should not go backward 461 times = [time.monotonic() for n in range(100)] 462 t1 = times[0] 463 for t2 in times[1:]: 464 self.assertGreaterEqual(t2, t1, "times=%s" % times) 465 t1 = t2 466 467 # monotonic() includes time elapsed during a sleep 468 t1 = time.monotonic() 469 time.sleep(0.5) 470 t2 = time.monotonic() 471 dt = t2 - t1 472 self.assertGreater(t2, t1) 473 # Issue #20101: On some Windows machines, dt may be slightly low 474 self.assertTrue(0.45 <= dt <= 1.0, dt) 475 476 # monotonic() is a monotonic but non adjustable clock 477 info = time.get_clock_info('monotonic') 478 self.assertTrue(info.monotonic) 479 self.assertFalse(info.adjustable) 480 481 def test_perf_counter(self): 482 time.perf_counter() 483 484 def test_process_time(self): 485 # process_time() should not include time spend during a sleep 486 start = time.process_time() 487 time.sleep(0.100) 488 stop = time.process_time() 489 # use 20 ms because process_time() has usually a resolution of 15 ms 490 # on Windows 491 self.assertLess(stop - start, 0.020) 492 493 info = time.get_clock_info('process_time') 494 self.assertTrue(info.monotonic) 495 self.assertFalse(info.adjustable) 496 497 def test_thread_time(self): 498 if not hasattr(time, 'thread_time'): 499 if sys.platform.startswith(('linux', 'win')): 500 self.fail("time.thread_time() should be available on %r" 501 % (sys.platform,)) 502 else: 503 self.skipTest("need time.thread_time") 504 505 # thread_time() should not include time spend during a sleep 506 start = time.thread_time() 507 time.sleep(0.100) 508 stop = time.thread_time() 509 # use 20 ms because thread_time() has usually a resolution of 15 ms 510 # on Windows 511 self.assertLess(stop - start, 0.020) 512 513 info = time.get_clock_info('thread_time') 514 self.assertTrue(info.monotonic) 515 self.assertFalse(info.adjustable) 516 517 @unittest.skipUnless(hasattr(time, 'clock_settime'), 518 'need time.clock_settime') 519 def test_monotonic_settime(self): 520 t1 = time.monotonic() 521 realtime = time.clock_gettime(time.CLOCK_REALTIME) 522 # jump backward with an offset of 1 hour 523 try: 524 time.clock_settime(time.CLOCK_REALTIME, realtime - 3600) 525 except PermissionError as err: 526 self.skipTest(err) 527 t2 = time.monotonic() 528 time.clock_settime(time.CLOCK_REALTIME, realtime) 529 # monotonic must not be affected by system clock updates 530 self.assertGreaterEqual(t2, t1) 531 532 def test_localtime_failure(self): 533 # Issue #13847: check for localtime() failure 534 invalid_time_t = None 535 for time_t in (-1, 2**30, 2**33, 2**60): 536 try: 537 time.localtime(time_t) 538 except OverflowError: 539 self.skipTest("need 64-bit time_t") 540 except OSError: 541 invalid_time_t = time_t 542 break 543 if invalid_time_t is None: 544 self.skipTest("unable to find an invalid time_t value") 545 546 self.assertRaises(OSError, time.localtime, invalid_time_t) 547 self.assertRaises(OSError, time.ctime, invalid_time_t) 548 549 # Issue #26669: check for localtime() failure 550 self.assertRaises(ValueError, time.localtime, float("nan")) 551 self.assertRaises(ValueError, time.ctime, float("nan")) 552 553 def test_get_clock_info(self): 554 clocks = ['clock', 'monotonic', 'perf_counter', 'process_time', 'time'] 555 556 for name in clocks: 557 if name == 'clock': 558 with self.assertWarns(DeprecationWarning): 559 info = time.get_clock_info('clock') 560 else: 561 info = time.get_clock_info(name) 562 563 #self.assertIsInstance(info, dict) 564 self.assertIsInstance(info.implementation, str) 565 self.assertNotEqual(info.implementation, '') 566 self.assertIsInstance(info.monotonic, bool) 567 self.assertIsInstance(info.resolution, float) 568 # 0.0 < resolution <= 1.0 569 self.assertGreater(info.resolution, 0.0) 570 self.assertLessEqual(info.resolution, 1.0) 571 self.assertIsInstance(info.adjustable, bool) 572 573 self.assertRaises(ValueError, time.get_clock_info, 'xxx') 574 575 576 class TestLocale(unittest.TestCase): 577 def setUp(self): 578 self.oldloc = locale.setlocale(locale.LC_ALL) 579 580 def tearDown(self): 581 locale.setlocale(locale.LC_ALL, self.oldloc) 582 583 def test_bug_3061(self): 584 try: 585 tmp = locale.setlocale(locale.LC_ALL, "fr_FR") 586 except locale.Error: 587 self.skipTest('could not set locale.LC_ALL to fr_FR') 588 # This should not cause an exception 589 time.strftime("%B", (2009,2,1,0,0,0,0,0,0)) 590 591 592 class _TestAsctimeYear: 593 _format = '%d' 594 595 def yearstr(self, y): 596 return time.asctime((y,) + (0,) * 8).split()[-1] 597 598 def test_large_year(self): 599 # Check that it doesn't crash for year > 9999 600 self.assertEqual(self.yearstr(12345), '12345') 601 self.assertEqual(self.yearstr(123456789), '123456789') 602 603 class _TestStrftimeYear: 604 605 # Issue 13305: For years < 1000, the value is not always 606 # padded to 4 digits across platforms. The C standard 607 # assumes year >= 1900, so it does not specify the number 608 # of digits. 609 610 if time.strftime('%Y', (1,) + (0,) * 8) == '0001': 611 _format = '%04d' 612 else: 613 _format = '%d' 614 615 def yearstr(self, y): 616 return time.strftime('%Y', (y,) + (0,) * 8) 617 618 def test_4dyear(self): 619 # Check that we can return the zero padded value. 620 if self._format == '%04d': 621 self.test_year('%04d') 622 else: 623 def year4d(y): 624 return time.strftime('%4Y', (y,) + (0,) * 8) 625 self.test_year('%04d', func=year4d) 626 627 def skip_if_not_supported(y): 628 msg = "strftime() is limited to [1; 9999] with Visual Studio" 629 # Check that it doesn't crash for year > 9999 630 try: 631 time.strftime('%Y', (y,) + (0,) * 8) 632 except ValueError: 633 cond = False 634 else: 635 cond = True 636 return unittest.skipUnless(cond, msg) 637 638 @skip_if_not_supported(10000) 639 def test_large_year(self): 640 return super().test_large_year() 641 642 @skip_if_not_supported(0) 643 def test_negative(self): 644 return super().test_negative() 645 646 del skip_if_not_supported 647 648 649 class _Test4dYear: 650 _format = '%d' 651 652 def test_year(self, fmt=None, func=None): 653 fmt = fmt or self._format 654 func = func or self.yearstr 655 self.assertEqual(func(1), fmt % 1) 656 self.assertEqual(func(68), fmt % 68) 657 self.assertEqual(func(69), fmt % 69) 658 self.assertEqual(func(99), fmt % 99) 659 self.assertEqual(func(999), fmt % 999) 660 self.assertEqual(func(9999), fmt % 9999) 661 662 def test_large_year(self): 663 self.assertEqual(self.yearstr(12345).lstrip('+'), '12345') 664 self.assertEqual(self.yearstr(123456789).lstrip('+'), '123456789') 665 self.assertEqual(self.yearstr(TIME_MAXYEAR).lstrip('+'), str(TIME_MAXYEAR)) 666 self.assertRaises(OverflowError, self.yearstr, TIME_MAXYEAR + 1) 667 668 def test_negative(self): 669 self.assertEqual(self.yearstr(-1), self._format % -1) 670 self.assertEqual(self.yearstr(-1234), '-1234') 671 self.assertEqual(self.yearstr(-123456), '-123456') 672 self.assertEqual(self.yearstr(-123456789), str(-123456789)) 673 self.assertEqual(self.yearstr(-1234567890), str(-1234567890)) 674 self.assertEqual(self.yearstr(TIME_MINYEAR), str(TIME_MINYEAR)) 675 # Modules/timemodule.c checks for underflow 676 self.assertRaises(OverflowError, self.yearstr, TIME_MINYEAR - 1) 677 with self.assertRaises(OverflowError): 678 self.yearstr(-TIME_MAXYEAR - 1) 679 680 681 class TestAsctime4dyear(_TestAsctimeYear, _Test4dYear, unittest.TestCase): 682 pass 683 684 class TestStrftime4dyear(_TestStrftimeYear, _Test4dYear, unittest.TestCase): 685 pass 686 687 688 class TestPytime(unittest.TestCase): 689 @unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support") 690 def test_localtime_timezone(self): 691 692 # Get the localtime and examine it for the offset and zone. 693 lt = time.localtime() 694 self.assertTrue(hasattr(lt, "tm_gmtoff")) 695 self.assertTrue(hasattr(lt, "tm_zone")) 696 697 # See if the offset and zone are similar to the module 698 # attributes. 699 if lt.tm_gmtoff is None: 700 self.assertTrue(not hasattr(time, "timezone")) 701 else: 702 self.assertEqual(lt.tm_gmtoff, -[time.timezone, time.altzone][lt.tm_isdst]) 703 if lt.tm_zone is None: 704 self.assertTrue(not hasattr(time, "tzname")) 705 else: 706 self.assertEqual(lt.tm_zone, time.tzname[lt.tm_isdst]) 707 708 # Try and make UNIX times from the localtime and a 9-tuple 709 # created from the localtime. Test to see that the times are 710 # the same. 711 t = time.mktime(lt); t9 = time.mktime(lt[:9]) 712 self.assertEqual(t, t9) 713 714 # Make localtimes from the UNIX times and compare them to 715 # the original localtime, thus making a round trip. 716 new_lt = time.localtime(t); new_lt9 = time.localtime(t9) 717 self.assertEqual(new_lt, lt) 718 self.assertEqual(new_lt.tm_gmtoff, lt.tm_gmtoff) 719 self.assertEqual(new_lt.tm_zone, lt.tm_zone) 720 self.assertEqual(new_lt9, lt) 721 self.assertEqual(new_lt.tm_gmtoff, lt.tm_gmtoff) 722 self.assertEqual(new_lt9.tm_zone, lt.tm_zone) 723 724 @unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support") 725 def test_strptime_timezone(self): 726 t = time.strptime("UTC", "%Z") 727 self.assertEqual(t.tm_zone, 'UTC') 728 t = time.strptime("+0500", "%z") 729 self.assertEqual(t.tm_gmtoff, 5 * 3600) 730 731 @unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support") 732 def test_short_times(self): 733 734 import pickle 735 736 # Load a short time structure using pickle. 737 st = b"ctime\nstruct_time\np0\n((I2007\nI8\nI11\nI1\nI24\nI49\nI5\nI223\nI1\ntp1\n(dp2\ntp3\nRp4\n." 738 lt = pickle.loads(st) 739 self.assertIs(lt.tm_gmtoff, None) 740 self.assertIs(lt.tm_zone, None) 741 742 743 @unittest.skipIf(_testcapi is None, 'need the _testcapi module') 744 class CPyTimeTestCase: 745 """ 746 Base class to test the C _PyTime_t API. 747 """ 748 OVERFLOW_SECONDS = None 749 750 def setUp(self): 751 from _testcapi import SIZEOF_TIME_T 752 bits = SIZEOF_TIME_T * 8 - 1 753 self.time_t_min = -2 ** bits 754 self.time_t_max = 2 ** bits - 1 755 756 def time_t_filter(self, seconds): 757 return (self.time_t_min <= seconds <= self.time_t_max) 758 759 def _rounding_values(self, use_float): 760 "Build timestamps used to test rounding." 761 762 units = [1, US_TO_NS, MS_TO_NS, SEC_TO_NS] 763 if use_float: 764 # picoseconds are only tested to pytime_converter accepting floats 765 units.append(1e-3) 766 767 values = ( 768 # small values 769 1, 2, 5, 7, 123, 456, 1234, 770 # 10^k - 1 771 9, 772 99, 773 999, 774 9999, 775 99999, 776 999999, 777 # test half even rounding near 0.5, 1.5, 2.5, 3.5, 4.5 778 499, 500, 501, 779 1499, 1500, 1501, 780 2500, 781 3500, 782 4500, 783 ) 784 785 ns_timestamps = [0] 786 for unit in units: 787 for value in values: 788 ns = value * unit 789 ns_timestamps.extend((-ns, ns)) 790 for pow2 in (0, 5, 10, 15, 22, 23, 24, 30, 33): 791 ns = (2 ** pow2) * SEC_TO_NS 792 ns_timestamps.extend(( 793 -ns-1, -ns, -ns+1, 794 ns-1, ns, ns+1 795 )) 796 for seconds in (_testcapi.INT_MIN, _testcapi.INT_MAX): 797 ns_timestamps.append(seconds * SEC_TO_NS) 798 if use_float: 799 # numbers with an exact representation in IEEE 754 (base 2) 800 for pow2 in (3, 7, 10, 15): 801 ns = 2.0 ** (-pow2) 802 ns_timestamps.extend((-ns, ns)) 803 804 # seconds close to _PyTime_t type limit 805 ns = (2 ** 63 // SEC_TO_NS) * SEC_TO_NS 806 ns_timestamps.extend((-ns, ns)) 807 808 return ns_timestamps 809 810 def _check_rounding(self, pytime_converter, expected_func, 811 use_float, unit_to_sec, value_filter=None): 812 813 def convert_values(ns_timestamps): 814 if use_float: 815 unit_to_ns = SEC_TO_NS / float(unit_to_sec) 816 values = [ns / unit_to_ns for ns in ns_timestamps] 817 else: 818 unit_to_ns = SEC_TO_NS // unit_to_sec 819 values = [ns // unit_to_ns for ns in ns_timestamps] 820 821 if value_filter: 822 values = filter(value_filter, values) 823 824 # remove duplicates and sort 825 return sorted(set(values)) 826 827 # test rounding 828 ns_timestamps = self._rounding_values(use_float) 829 valid_values = convert_values(ns_timestamps) 830 for time_rnd, decimal_rnd in ROUNDING_MODES : 831 with decimal.localcontext() as context: 832 context.rounding = decimal_rnd 833 834 for value in valid_values: 835 debug_info = {'value': value, 'rounding': decimal_rnd} 836 try: 837 result = pytime_converter(value, time_rnd) 838 expected = expected_func(value) 839 except Exception as exc: 840 self.fail("Error on timestamp conversion: %s" % debug_info) 841 self.assertEqual(result, 842 expected, 843 debug_info) 844 845 # test overflow 846 ns = self.OVERFLOW_SECONDS * SEC_TO_NS 847 ns_timestamps = (-ns, ns) 848 overflow_values = convert_values(ns_timestamps) 849 for time_rnd, _ in ROUNDING_MODES : 850 for value in overflow_values: 851 debug_info = {'value': value, 'rounding': time_rnd} 852 with self.assertRaises(OverflowError, msg=debug_info): 853 pytime_converter(value, time_rnd) 854 855 def check_int_rounding(self, pytime_converter, expected_func, 856 unit_to_sec=1, value_filter=None): 857 self._check_rounding(pytime_converter, expected_func, 858 False, unit_to_sec, value_filter) 859 860 def check_float_rounding(self, pytime_converter, expected_func, 861 unit_to_sec=1, value_filter=None): 862 self._check_rounding(pytime_converter, expected_func, 863 True, unit_to_sec, value_filter) 864 865 def decimal_round(self, x): 866 d = decimal.Decimal(x) 867 d = d.quantize(1) 868 return int(d) 869 870 871 class TestCPyTime(CPyTimeTestCase, unittest.TestCase): 872 """ 873 Test the C _PyTime_t API. 874 """ 875 # _PyTime_t is a 64-bit signed integer 876 OVERFLOW_SECONDS = math.ceil((2**63 + 1) / SEC_TO_NS) 877 878 def test_FromSeconds(self): 879 from _testcapi import PyTime_FromSeconds 880 881 # PyTime_FromSeconds() expects a C int, reject values out of range 882 def c_int_filter(secs): 883 return (_testcapi.INT_MIN <= secs <= _testcapi.INT_MAX) 884 885 self.check_int_rounding(lambda secs, rnd: PyTime_FromSeconds(secs), 886 lambda secs: secs * SEC_TO_NS, 887 value_filter=c_int_filter) 888 889 # test nan 890 for time_rnd, _ in ROUNDING_MODES: 891 with self.assertRaises(TypeError): 892 PyTime_FromSeconds(float('nan')) 893 894 def test_FromSecondsObject(self): 895 from _testcapi import PyTime_FromSecondsObject 896 897 self.check_int_rounding( 898 PyTime_FromSecondsObject, 899 lambda secs: secs * SEC_TO_NS) 900 901 self.check_float_rounding( 902 PyTime_FromSecondsObject, 903 lambda ns: self.decimal_round(ns * SEC_TO_NS)) 904 905 # test nan 906 for time_rnd, _ in ROUNDING_MODES: 907 with self.assertRaises(ValueError): 908 PyTime_FromSecondsObject(float('nan'), time_rnd) 909 910 def test_AsSecondsDouble(self): 911 from _testcapi import PyTime_AsSecondsDouble 912 913 def float_converter(ns): 914 if abs(ns) % SEC_TO_NS == 0: 915 return float(ns // SEC_TO_NS) 916 else: 917 return float(ns) / SEC_TO_NS 918 919 self.check_int_rounding(lambda ns, rnd: PyTime_AsSecondsDouble(ns), 920 float_converter, 921 NS_TO_SEC) 922 923 # test nan 924 for time_rnd, _ in ROUNDING_MODES: 925 with self.assertRaises(TypeError): 926 PyTime_AsSecondsDouble(float('nan')) 927 928 def create_decimal_converter(self, denominator): 929 denom = decimal.Decimal(denominator) 930 931 def converter(value): 932 d = decimal.Decimal(value) / denom 933 return self.decimal_round(d) 934 935 return converter 936 937 def test_AsTimeval(self): 938 from _testcapi import PyTime_AsTimeval 939 940 us_converter = self.create_decimal_converter(US_TO_NS) 941 942 def timeval_converter(ns): 943 us = us_converter(ns) 944 return divmod(us, SEC_TO_US) 945 946 if sys.platform == 'win32': 947 from _testcapi import LONG_MIN, LONG_MAX 948 949 # On Windows, timeval.tv_sec type is a C long 950 def seconds_filter(secs): 951 return LONG_MIN <= secs <= LONG_MAX 952 else: 953 seconds_filter = self.time_t_filter 954 955 self.check_int_rounding(PyTime_AsTimeval, 956 timeval_converter, 957 NS_TO_SEC, 958 value_filter=seconds_filter) 959 960 @unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec'), 961 'need _testcapi.PyTime_AsTimespec') 962 def test_AsTimespec(self): 963 from _testcapi import PyTime_AsTimespec 964 965 def timespec_converter(ns): 966 return divmod(ns, SEC_TO_NS) 967 968 self.check_int_rounding(lambda ns, rnd: PyTime_AsTimespec(ns), 969 timespec_converter, 970 NS_TO_SEC, 971 value_filter=self.time_t_filter) 972 973 def test_AsMilliseconds(self): 974 from _testcapi import PyTime_AsMilliseconds 975 976 self.check_int_rounding(PyTime_AsMilliseconds, 977 self.create_decimal_converter(MS_TO_NS), 978 NS_TO_SEC) 979 980 def test_AsMicroseconds(self): 981 from _testcapi import PyTime_AsMicroseconds 982 983 self.check_int_rounding(PyTime_AsMicroseconds, 984 self.create_decimal_converter(US_TO_NS), 985 NS_TO_SEC) 986 987 988 class TestOldPyTime(CPyTimeTestCase, unittest.TestCase): 989 """ 990 Test the old C _PyTime_t API: _PyTime_ObjectToXXX() functions. 991 """ 992 993 # time_t is a 32-bit or 64-bit signed integer 994 OVERFLOW_SECONDS = 2 ** 64 995 996 def test_object_to_time_t(self): 997 from _testcapi import pytime_object_to_time_t 998 999 self.check_int_rounding(pytime_object_to_time_t, 1000 lambda secs: secs, 1001 value_filter=self.time_t_filter) 1002 1003 self.check_float_rounding(pytime_object_to_time_t, 1004 self.decimal_round, 1005 value_filter=self.time_t_filter) 1006 1007 def create_converter(self, sec_to_unit): 1008 def converter(secs): 1009 floatpart, intpart = math.modf(secs) 1010 intpart = int(intpart) 1011 floatpart *= sec_to_unit 1012 floatpart = self.decimal_round(floatpart) 1013 if floatpart < 0: 1014 floatpart += sec_to_unit 1015 intpart -= 1 1016 elif floatpart >= sec_to_unit: 1017 floatpart -= sec_to_unit 1018 intpart += 1 1019 return (intpart, floatpart) 1020 return converter 1021 1022 def test_object_to_timeval(self): 1023 from _testcapi import pytime_object_to_timeval 1024 1025 self.check_int_rounding(pytime_object_to_timeval, 1026 lambda secs: (secs, 0), 1027 value_filter=self.time_t_filter) 1028 1029 self.check_float_rounding(pytime_object_to_timeval, 1030 self.create_converter(SEC_TO_US), 1031 value_filter=self.time_t_filter) 1032 1033 # test nan 1034 for time_rnd, _ in ROUNDING_MODES: 1035 with self.assertRaises(ValueError): 1036 pytime_object_to_timeval(float('nan'), time_rnd) 1037 1038 def test_object_to_timespec(self): 1039 from _testcapi import pytime_object_to_timespec 1040 1041 self.check_int_rounding(pytime_object_to_timespec, 1042 lambda secs: (secs, 0), 1043 value_filter=self.time_t_filter) 1044 1045 self.check_float_rounding(pytime_object_to_timespec, 1046 self.create_converter(SEC_TO_NS), 1047 value_filter=self.time_t_filter) 1048 1049 # test nan 1050 for time_rnd, _ in ROUNDING_MODES: 1051 with self.assertRaises(ValueError): 1052 pytime_object_to_timespec(float('nan'), time_rnd) 1053 1054 1055 if __name__ == "__main__": 1056 unittest.main() 1057