diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index b37ab0cd02df2c..0fc1445e6b0bf5 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -1111,6 +1111,9 @@ def test_extreme_tzstr(self): "AAA4BBB,J1/2,J1/14", "AAA4BBB,J20/2,J365/2", "AAA4BBB,J365/2,J365/14", + # Leading-zero day-of-year + "AAA4BBB,J001/2,J065/2", + "AAA4BBB,001/2,065/2", # Extreme transition hour "AAA4BBB,J60/167,J300/2", "AAA4BBB,J60/+167,J300/2", @@ -1209,6 +1212,15 @@ def test_invalid_tzstr(self): # Invalid julian offset "AAA4BBB,J0/2,J20/2", "AAA4BBB,J20/2,J366/2", + # gh-152847: non-digit day-of-year + "AAA4BBB,J1_0,J300/2", + "AAA4BBB,J60/2,J30_0/2", + "AAA4BBB,1_0,J300/2", + "AAA4BBB,J+1,J300/2", + "AAA4BBB,J 1,J300/2", + "AAA4BBB, 1,J300/2", + "AAA4BBB,J0001,J300/2", + "AAA4BBB,0001,J300/2", # Invalid transition time "AAA4BBB,J60/2/3,J300/2", "AAA4BBB,J60/2,J300/2/3", @@ -1248,6 +1260,15 @@ def test_invalid_tzstr_non_ascii_abbr(self): with self.assertRaisesRegex(ValueError, expected): self.zone_from_tzstr(tzstr, encoding="utf-8") + def test_invalid_tzstr_non_ascii_dst_date(self): + tzstr = "AAA4BBB,J١,J300/2" + if self.module is py_zoneinfo: + expected = re.escape(tzstr) + else: + expected = re.escape(repr(tzstr.encode("utf-8"))) + with self.assertRaisesRegex(ValueError, expected): + self.zone_from_tzstr(tzstr, encoding="utf-8") + @classmethod def _populate_test_cases(cls): # This method uses a somewhat unusual style in that it populates the diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index 90cf2bbf8f5d0d..48154775568b6d 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -720,6 +720,8 @@ def _parse_dst_start_end(dststr): else: n_is_julian = False + if re.fullmatch(r"\d{1,3}", date, re.ASCII) is None: + raise ValueError(f"Invalid dst start/end date: {dststr}") doy = int(date) offset = _DayOffset(doy, n_is_julian) diff --git a/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst b/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst new file mode 100644 index 00000000000000..3f20d78a201e84 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst @@ -0,0 +1,3 @@ +Reject a POSIX TZ transition rule with non-digit characters in the +day-of-year field in the pure-Python :mod:`zoneinfo` parser. Patch by +tonghuaroot.