| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent a834e2d commit 83c0247
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1754,7 +1754,7 @@ def _fromtimestamp(cls, t, utc, tz): | |||
| 1754 | 1754 | y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) | |
| 1755 | 1755 | ss = min(ss, 59) # clamp out leap seconds if the platform has them | |
| 1756 | 1756 | result = cls(y, m, d, hh, mm, ss, us, tz) | |
| 1757 | - if tz is None: | ||
| 1757 | + if tz is None and not utc: | ||
| 1758 | 1758 | # As of version 2015f max fold in IANA database is | |
| 1759 | 1759 | # 23 hours at 1969-09-30 13:00:00 in Kwajalein. | |
| 1760 | 1760 | # Let's probe 24 hours in the past to detect a transition: | |
@@ -1775,7 +1775,7 @@ def _fromtimestamp(cls, t, utc, tz): | |||
| 1775 | 1775 | probe2 = cls(y, m, d, hh, mm, ss, us, tz) | |
| 1776 | 1776 | if probe2 == result: | |
| 1777 | 1777 | result._fold = 1 | |
| 1778 | - else: | ||
| 1778 | + elif tz is not None: | ||
| 1779 | 1779 | result = tz.fromutc(result) | |
| 1780 | 1780 | return result | |
| 1781 | 1781 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2515,45 +2515,101 @@ def test_microsecond_rounding(self): | |||
| 2515 | 2515 | self.assertEqual(t.microsecond, 7812) | |
| 2516 | 2516 | ||
| 2517 | 2517 | def test_timestamp_limits(self): | |
| 2518 | - # minimum timestamp | ||
| 2519 | - min_dt = self.theclass.min.replace(tzinfo=timezone.utc) | ||
| 2518 | + with self.subTest("minimum UTC"): | ||
| 2519 | + min_dt = self.theclass.min.replace(tzinfo=timezone.utc) | ||
| 2520 | + min_ts = min_dt.timestamp() | ||
| 2521 | + | ||
| 2522 | + # This test assumes that datetime.min == 0000-01-01T00:00:00.00 | ||
| 2523 | + # If that assumption changes, this value can change as well | ||
| 2524 | + self.assertEqual(min_ts, -62135596800) | ||
| 2525 | + | ||
| 2526 | + with self.subTest("maximum UTC"): | ||
| 2527 | + # Zero out microseconds to avoid rounding issues | ||
| 2528 | + max_dt = self.theclass.max.replace(tzinfo=timezone.utc, | ||
| 2529 | + microsecond=0) | ||
| 2530 | + max_ts = max_dt.timestamp() | ||
| 2531 | + | ||
| 2532 | + # This test assumes that datetime.max == 9999-12-31T23:59:59.999999 | ||
| 2533 | + # If that assumption changes, this value can change as well | ||
| 2534 | + self.assertEqual(max_ts, 253402300799.0) | ||
| 2535 | + | ||
| 2536 | + def test_fromtimestamp_limits(self): | ||
| 2537 | + try: | ||
| 2538 | + self.theclass.fromtimestamp(-2**32 - 1) | ||
| 2539 | + except (OSError, OverflowError): | ||
| 2540 | + self.skipTest("Test not valid on this platform") | ||
| 2541 | + | ||
| 2542 | + # XXX: Replace these with datetime.{min,max}.timestamp() when we solve | ||
| 2543 | + # the issue with gh-91012 | ||
| 2544 | + min_dt = self.theclass.min + timedelta(days=1) | ||
| 2520 | 2545 | min_ts = min_dt.timestamp() | |
| 2546 | + | ||
| 2547 | + max_dt = self.theclass.max.replace(microsecond=0) | ||
| 2548 | + max_ts = ((self.theclass.max - timedelta(hours=23)).timestamp() + | ||
| 2549 | + timedelta(hours=22, minutes=59, seconds=59).total_seconds()) | ||
| 2550 | + | ||
| 2551 | + for (test_name, ts, expected) in [ | ||
| 2552 | + ("minimum", min_ts, min_dt), | ||
| 2553 | + ("maximum", max_ts, max_dt), | ||
| 2554 | + ]: | ||
| 2555 | + with self.subTest(test_name, ts=ts, expected=expected): | ||
| 2556 | + actual = self.theclass.fromtimestamp(ts) | ||
| 2557 | + | ||
| 2558 | + self.assertEqual(actual, expected) | ||
| 2559 | + | ||
| 2560 | + # Test error conditions | ||
| 2561 | + test_cases = [ | ||
| 2562 | + ("Too small by a little", min_ts - timedelta(days=1, hours=12).total_seconds()), | ||
| 2563 | + ("Too small by a lot", min_ts - timedelta(days=400).total_seconds()), | ||
| 2564 | + ("Too big by a little", max_ts + timedelta(days=1).total_seconds()), | ||
| 2565 | + ("Too big by a lot", max_ts + timedelta(days=400).total_seconds()), | ||
| 2566 | + ] | ||
| 2567 | + | ||
| 2568 | + for test_name, ts in test_cases: | ||
| 2569 | + with self.subTest(test_name, ts=ts): | ||
| 2570 | + with self.assertRaises((ValueError, OverflowError)): | ||
| 2571 | + # converting a Python int to C time_t can raise a | ||
| 2572 | + # OverflowError, especially on 32-bit platforms. | ||
| 2573 | + self.theclass.fromtimestamp(ts) | ||
| 2574 | + | ||
| 2575 | + def test_utcfromtimestamp_limits(self): | ||
| 2521 | 2576 | try: | |
| 2522 | - # date 0001-01-01 00:00:00+00:00: timestamp=-62135596800 | ||
| 2523 | - self.assertEqual(self.theclass.fromtimestamp(min_ts, tz=timezone.utc), | ||
| 2524 | - min_dt) | ||
| 2525 | - except (OverflowError, OSError) as exc: | ||
| 2526 | - # the date 0001-01-01 doesn't fit into 32-bit time_t, | ||
| 2527 | - # or platform doesn't support such very old date | ||
| 2528 | - self.skipTest(str(exc)) | ||
| 2529 | - | ||
| 2530 | - # maximum timestamp: set seconds to zero to avoid rounding issues | ||
| 2531 | - max_dt = self.theclass.max.replace(tzinfo=timezone.utc, | ||
| 2532 | - second=0, microsecond=0) | ||
| 2577 | + self.theclass.utcfromtimestamp(-2**32 - 1) | ||
| 2578 | + except (OSError, OverflowError): | ||
| 2579 | + self.skipTest("Test not valid on this platform") | ||
| 2580 | + | ||
| 2581 | + min_dt = self.theclass.min.replace(tzinfo=timezone.utc) | ||
| 2582 | + min_ts = min_dt.timestamp() | ||
| 2583 | + | ||
| 2584 | + max_dt = self.theclass.max.replace(microsecond=0, tzinfo=timezone.utc) | ||
| 2533 | 2585 | max_ts = max_dt.timestamp() | |
| 2534 | - # date 9999-12-31 23:59:00+00:00: timestamp 253402300740 | ||
| 2535 | - self.assertEqual(self.theclass.fromtimestamp(max_ts, tz=timezone.utc), | ||
| 2536 | - max_dt) | ||
| 2537 | - | ||
| 2538 | - # number of seconds greater than 1 year: make sure that the new date | ||
| 2539 | - # is not valid in datetime.datetime limits | ||
| 2540 | - delta = 3600 * 24 * 400 | ||
| 2541 | - | ||
| 2542 | - # too small | ||
| 2543 | - ts = min_ts - delta | ||
| 2544 | - # converting a Python int to C time_t can raise a OverflowError, | ||
| 2545 | - # especially on 32-bit platforms. | ||
| 2546 | - with self.assertRaises((ValueError, OverflowError)): | ||
| 2547 | - self.theclass.fromtimestamp(ts) | ||
| 2548 | - with self.assertRaises((ValueError, OverflowError)): | ||
| 2549 | - self.theclass.utcfromtimestamp(ts) | ||
| 2550 | - | ||
| 2551 | - # too big | ||
| 2552 | - ts = max_dt.timestamp() + delta | ||
| 2553 | - with self.assertRaises((ValueError, OverflowError)): | ||
| 2554 | - self.theclass.fromtimestamp(ts) | ||
| 2555 | - with self.assertRaises((ValueError, OverflowError)): | ||
| 2556 | - self.theclass.utcfromtimestamp(ts) | ||
| 2586 | + | ||
| 2587 | + for (test_name, ts, expected) in [ | ||
| 2588 | + ("minimum", min_ts, min_dt.replace(tzinfo=None)), | ||
| 2589 | + ("maximum", max_ts, max_dt.replace(tzinfo=None)), | ||
| 2590 | + ]: | ||
| 2591 | + with self.subTest(test_name, ts=ts, expected=expected): | ||
| 2592 | + try: | ||
| 2593 | + actual = self.theclass.utcfromtimestamp(ts) | ||
| 2594 | + except (OSError, OverflowError) as exc: | ||
| 2595 | + self.skipTest(str(exc)) | ||
| 2596 | + | ||
| 2597 | + self.assertEqual(actual, expected) | ||
| 2598 | + | ||
| 2599 | + # Test error conditions | ||
| 2600 | + test_cases = [ | ||
| 2601 | + ("Too small by a little", min_ts - 1), | ||
| 2602 | + ("Too small by a lot", min_ts - timedelta(days=400).total_seconds()), | ||
| 2603 | + ("Too big by a little", max_ts + 1), | ||
| 2604 | + ("Too big by a lot", max_ts + timedelta(days=400).total_seconds()), | ||
| 2605 | + ] | ||
| 2606 | + | ||
| 2607 | + for test_name, ts in test_cases: | ||
| 2608 | + with self.subTest(test_name, ts=ts): | ||
| 2609 | + with self.assertRaises((ValueError, OverflowError)): | ||
| 2610 | + # converting a Python int to C time_t can raise a | ||
| 2611 | + # OverflowError, especially on 32-bit platforms. | ||
| 2612 | + self.theclass.utcfromtimestamp(ts) | ||
| 2557 | 2613 | ||
| 2558 | 2614 | def test_insane_fromtimestamp(self): | |
| 2559 | 2615 | # It's possible that some platform maps time_t to double, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,6 @@ | |||
| 1 | + Remove an unhandled error case in the C implementation of calls to | ||
| 2 | + :meth:`datetime.fromtimestamp <datetime.datetime.fromtimestamp>` with no time | ||
| 3 | + zone (i.e. getting a local time from an epoch timestamp). This should have no | ||
| 4 | + user-facing effect other than giving a possibly more accurate error message | ||
| 5 | + when called with timestamps that fall on 10000-01-01 in the local time. Patch | ||
| 6 | + by Paul Ganssle. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,5 @@ | |||
| 1 | + :meth:`~datetime.datetime.utcfromtimestamp` no longer attempts to resolve | ||
| 2 | + ``fold`` in the pure Python implementation, since the fold is never 1 in UTC. | ||
| 3 | + In addition to being slightly faster in the common case, this also prevents | ||
| 4 | + some errors when the timestamp is close to :attr:`datetime.min | ||
| 5 | + <datetime.datetime.min>`. Patch by Paul Ganssle. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5071,6 +5071,10 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, | |||
| 5071 | 5071 | ||
| 5072 | 5072 | result_seconds = utc_to_seconds(year, month, day, | |
| 5073 | 5073 | hour, minute, second); | |
| 5074 | + if (result_seconds == -1 && PyErr_Occurred()) { | ||
| 5075 | + return NULL; | ||
| 5076 | + } | ||
| 5077 | + | ||
| 5074 | 5078 | /* Probe max_fold_seconds to detect a fold. */ | |
| 5075 | 5079 | probe_seconds = local(epoch + timet - max_fold_seconds); | |
| 5076 | 5080 | if (probe_seconds == -1) | |
| Back | FazBrowse Home | New Git URL |
0 commit comments