diff --git a/arrow/parser.py b/arrow/parser.py index 645e3da7..68ed6e8f 100644 --- a/arrow/parser.py +++ b/arrow/parser.py @@ -734,7 +734,7 @@ def _generate_choice_re( class TzinfoParser: _TZINFO_RE: ClassVar[Pattern[str]] = re.compile( - r"^(?:\(UTC)*([\+\-])?(\d{2})(?:\:?(\d{2}))?" + r"^(?:(\(UTC))*([\+\-])?(\d{2})(?:\:?(\d{2}))?(?(1)\)|$)" ) @classmethod @@ -754,7 +754,7 @@ def parse(cls, tzinfo_string: str) -> dt_tzinfo: sign: Optional[str] hours: str minutes: Union[str, int, None] - sign, hours, minutes = iso_match.groups() + _, sign, hours, minutes = iso_match.groups() seconds = int(hours) * 3600 + int(minutes or 0) * 60 if sign == "-": diff --git a/tests/test_parser.py b/tests/test_parser.py index 1932b450..01243bb6 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -1316,9 +1316,8 @@ def test_parse_utc(self): assert self.parser.parse("UTC") == tz.tzutc() def test_parse_utc_withoffset(self): - assert self.parser.parse("(UTC+01:00") == tz.tzoffset(None, 3600) - assert self.parser.parse("(UTC-01:00") == tz.tzoffset(None, -3600) - assert self.parser.parse("(UTC+01:00") == tz.tzoffset(None, 3600) + assert self.parser.parse("(UTC-01:00)") == tz.tzoffset(None, -3600) + assert self.parser.parse("(UTC+01:00)") == tz.tzoffset(None, 3600) assert self.parser.parse( "(UTC+01:00) Amsterdam, Berlin, Bern, Rom, Stockholm, Wien" ) == tz.tzoffset(None, 3600) @@ -1341,8 +1340,23 @@ def test_parse_str(self): assert self.parser.parse("US/Pacific") == tz.gettz("US/Pacific") def test_parse_fails(self): - with pytest.raises(parser.ParserError): - self.parser.parse("fail") + pytest.raises(parser.ParserError, self.parser.parse, "fail") + pytest.raises(parser.ParserError, self.parser.parse, "+03:00.34") + pytest.raises(parser.ParserError, self.parser.parse, "+03:00 ") + pytest.raises( + parser.ParserError, + self.parser.parse, + "(UTC+01:00 Amsterdam, Berlin, Bern, Rom, Stockholm, Wien", + ) + pytest.raises( + parser.ParserError, + self.parser.parse, + "+01:00 Amsterdam, Berlin, Bern, Rom, Stockholm, Wien", + ) + + # These get parsed by dateutil.tz.gettz(), albeit it probably shouldn't + # pytest.raises(parser.ParserError, self.parser.parse, "(UTC+01:00") + # pytest.raises(parser.ParserError, self.parser.parse, "(UTC+01:00 Amsterdam") @pytest.mark.usefixtures("dt_parser")