From e56504a65a4edd0d27acf34ffd8562bf4de93ce0 Mon Sep 17 00:00:00 2001 From: Sskift <163287349+Sskift@users.noreply.github.com> Date: Tue, 3 Nov 2026 01:44:58 +0800 Subject: [PATCH] Parse UTC designators in from_format offset tokens --- src/pendulum/formatting/formatter.py | 3 +++ tests/datetime/test_from_format.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/pendulum/formatting/formatter.py b/src/pendulum/formatting/formatter.py index b09977d0d..33785de6e 100644 --- a/src/pendulum/formatting/formatter.py +++ b/src/pendulum/formatting/formatter.py @@ -594,6 +594,9 @@ def _get_parsed_value( elif token in ["X", "x"]: parsed["timestamp"] = parsed_token elif token in ["ZZ", "Z"]: + if value in ["Z", "z"]: + value = "+00:00" + negative = bool(value.startswith("-")) tz = value[1:] if ":" not in tz: diff --git a/tests/datetime/test_from_format.py b/tests/datetime/test_from_format.py index ecf59632a..34f70292e 100644 --- a/tests/datetime/test_from_format.py +++ b/tests/datetime/test_from_format.py @@ -37,6 +37,20 @@ def test_from_format_with_timezone(): assert d.timezone_name == "Europe/London" +@pytest.mark.parametrize("token", ["Z", "ZZ"]) +@pytest.mark.parametrize("offset", ["Z", "z", "+00:00", "+0000"]) +@pytest.mark.parametrize("default_tz", ["UTC", "Europe/Paris"]) +def test_from_format_with_utc_designator(token, offset, default_tz): + d = pendulum.from_format( + f"1975-05-21T22:32:11{offset}", + f"YYYY-MM-DD[T]HH:mm:ss{token}", + tz=default_tz, + ) + + assert_datetime(d, 1975, 5, 21, 22, 32, 11) + assert d.offset == 0 + + def test_from_format_with_square_bracket_in_timezone(): with pytest.raises(ValueError, match=r"^String does not match format"): pendulum.from_format(