diff --git a/arrow/parser.py b/arrow/parser.py index fc3774b09..f1b93548d 100644 --- a/arrow/parser.py +++ b/arrow/parser.py @@ -161,8 +161,12 @@ class DateTimeParser: _TWO_DIGIT_RE: ClassVar[Pattern[str]] = re.compile(r"\d{2}") _THREE_DIGIT_RE: ClassVar[Pattern[str]] = re.compile(r"\d{3}") _FOUR_DIGIT_RE: ClassVar[Pattern[str]] = re.compile(r"\d{4}") - _TZ_Z_RE: ClassVar[Pattern[str]] = re.compile(r"([\+\-])(\d{2})(?:(\d{2}))?|Z") - _TZ_ZZ_RE: ClassVar[Pattern[str]] = re.compile(r"([\+\-])(\d{2})(?:\:(\d{2}))?|Z") + _TZ_Z_RE: ClassVar[Pattern[str]] = re.compile( + r"([\+\-])(\d{2})(?:(\d{2})(?:\d{2})?)?|Z" + ) + _TZ_ZZ_RE: ClassVar[Pattern[str]] = re.compile( + r"([\+\-])(\d{2})(?:\:(\d{2})(?:\:\d{2})?)?|Z" + ) _TZ_NAME_RE: ClassVar[Pattern[str]] = re.compile(r"\w[\w+\-/]+") # NOTE: timestamps cannot be parsed from natural language strings (by removing the ^...$) because it will # break cases like "15 Jul 2000" and a format list (see issue #447) @@ -888,7 +892,7 @@ class TzinfoParser: """ _TZINFO_RE: ClassVar[Pattern[str]] = re.compile( - r"^(?:\(UTC)*([\+\-])?(\d{2})(?:\:?(\d{2}))?" + r"^(?:\(UTC)*([\+\-])?(\d{2})(?:\:?(\d{2})(?:\:?(\d{2}))?)?" ) @classmethod @@ -917,8 +921,13 @@ def parse(cls, tzinfo_string: str) -> dt_tzinfo: sign: Optional[str] hours: str minutes: Union[str, int, None] - sign, hours, minutes = iso_match.groups() - seconds = int(hours) * 3600 + int(minutes or 0) * 60 + seconds_part: Union[str, int, None] + sign, hours, minutes, seconds_part = iso_match.groups() + seconds = ( + int(hours) * 3600 + + int(minutes or 0) * 60 + + int(seconds_part or 0) + ) if sign == "-": seconds *= -1 diff --git a/tests/test_parser.py b/tests/test_parser.py index 7038d880f..de91a2372 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -1260,6 +1260,14 @@ def test_iso8601_basic_format(self): 2018, 5, 17, 10, 55, 13, tzinfo=tz.tzoffset(None, -25200) ) + assert self.parser.parse_iso("1935-01-01T00:00:00-03:30:52") == datetime( + 1935, 1, 1, 0, 0, 0, tzinfo=timezone(timedelta(seconds=-12652)) + ) + + assert self.parser.parse_iso("19350101T000000-033052") == datetime( + 1935, 1, 1, 0, 0, 0, tzinfo=timezone(timedelta(seconds=-12652)) + ) + # ordinal in basic format: YYYYDDDD assert self.parser.parse_iso("1998136") == datetime(1998, 5, 16) @@ -1346,6 +1354,10 @@ def test_parse_iso(self): assert self.parser.parse("+01") == timezone(timedelta(seconds=3600)) assert self.parser.parse("-01") == timezone(timedelta(seconds=-3600)) + assert self.parser.parse("+01:02:03") == timezone(timedelta(seconds=3723)) + assert self.parser.parse("-03:30:52") == timezone(timedelta(seconds=-12652)) + assert self.parser.parse("-033052") == timezone(timedelta(seconds=-12652)) + def test_parse_str(self): assert self.parser.parse("US/Pacific") == ZoneInfo("US/Pacific")