https://github.com/python/cpython/commit/598856c7e44639b3c46bfffd8958d77d859d2c2c
commit: 598856c7e44639b3c46bfffd8958d77d859d2c2c
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: StanFromIreland <[email protected]>
date: 2026-07-02T18:31:47Z
summary:

[3.15] gh-152847: Reject POSIX TZ rule with non-digit day-of-year in 
`_zoneinfo.py` (GH-152848) (#152910)

(cherry picked from commit 31864bd9a683c93bd9b294fb5bcf6857493c15ff)

Co-authored-by: tonghuaroot (童话) <[email protected]>
Co-authored-by: Stan Ulbrych <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst
M Lib/test/test_zoneinfo/test_zoneinfo.py
M Lib/zoneinfo/_zoneinfo.py

diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py 
b/Lib/test/test_zoneinfo/test_zoneinfo.py
index 813b56501308f9e..a10f434eb27590d 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 90cf2bbf8f5d0d1..48154775568b6dc 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 000000000000000..3f20d78a201e84c
--- /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.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to