diff --git a/crates/stdlib/src/_zoneinfo.rs b/crates/stdlib/src/_zoneinfo.rs index 9ab94cbefcd..aea7db10b4a 100644 --- a/crates/stdlib/src/_zoneinfo.rs +++ b/crates/stdlib/src/_zoneinfo.rs @@ -552,6 +552,9 @@ mod _zoneinfo { parser.bump(); } let end = parser.i; + if end == start { + return None; + } parser.bump(); return Some(String::from_utf8_lossy(&parser.bytes[start..end]).into_owned()); } diff --git a/extra_tests/snippets/stdlib_zoneinfo.py b/extra_tests/snippets/stdlib_zoneinfo.py new file mode 100644 index 00000000000..c8004585f81 --- /dev/null +++ b/extra_tests/snippets/stdlib_zoneinfo.py @@ -0,0 +1,19 @@ +import io +import struct +from zoneinfo import ZoneInfo + +from testutils import assert_raises + +# Minimal TZif v3 data with no transitions and a POSIX rule in the footer. +header = (b"TZif3" + b"\0" * 15 + struct.pack(">6l", 0, 0, 0, 0, 0, 0)) * 2 + + +def zone_from_rule(rule): + return ZoneInfo.from_file(io.BytesIO(header + b"\n" + rule + b"\n")) + + +for rule in (b"<>5", b"AAA4<>,M3.2.0/2,M11.1.0/3"): + assert_raises(ValueError, zone_from_rule, rule) + +# Quoting still permits nonempty numeric abbreviations. +assert zone_from_rule(b"<+05>-5").tzname(None) == "+05"