diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index 26bcd1e491d78c..606ca79f34e13f 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -1989,7 +1989,11 @@ def _mktime(self): t = (self - epoch) // timedelta(0, 1) def local(u): y, m, d, hh, mm, ss = _time.localtime(u)[:6] - return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1) + try: + return ((datetime(y, m, d, hh, mm, ss) - epoch) // + timedelta(0, 1)) + except (ValueError, OverflowError): + return u # Our goal is to solve t = local(u) for u. a = local(t) - t diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 84eb872f964ba1..789ad16f8f7a3b 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -3122,6 +3122,18 @@ def dst(self, dt): return 1 with self.assertRaises(TypeError): dt_broken.astimezone() + dt_big = self.theclass(9999, 12, 31, 23, 59, 59) + dt_big_utc = dt_big.replace(hour=19, + tzinfo=timezone(timedelta(hours=-4), 'EDT')) + self.assertEqual(dt_big_utc, + dt_big.replace(tzinfo=timezone.utc).astimezone()) + + other_tz = timezone(timedelta(hours=+4), '+04') + dt_other_tz = dt_big.replace(tzinfo=other_tz) + dt_utc_tz = dt_big.replace(tzinfo=timezone.utc) + self.assertEqual(dt_other_tz, dt_other_tz.astimezone(tz=other_tz)) + self.assertEqual(dt_utc_tz, dt_utc_tz.astimezone(tz=timezone.utc)) + def test_subclass_datetime(self): class C(self.theclass): diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 83b92fe606984c..accfc1bb1fcf49 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5415,6 +5415,7 @@ local(long long u) { struct tm local_time; time_t t; + long long old_u = u; u -= epoch; t = u; if (t != u) { @@ -5424,7 +5425,14 @@ local(long long u) } if (_PyTime_localtime(t, &local_time) != 0) return -1; - return utc_to_seconds(local_time.tm_year + 1900, + + // Check edge cases + int year = local_time.tm_year + 1900; + if (year < MINYEAR || year > MAXYEAR) { + Py_DECREF(year); + return old_u; + } + return utc_to_seconds(year, local_time.tm_mon + 1, local_time.tm_mday, local_time.tm_hour,