diff --git a/arrow/parser.py b/arrow/parser.py index fc3774b09..07f90d64d 100644 --- a/arrow/parser.py +++ b/arrow/parser.py @@ -713,7 +713,7 @@ def _build_datetime(parts: _Parts) -> datetime: # day not given, default to 1 _day = 1 - date_string = f"{year}-{week}-{_day}" + date_string = f"{year:04d}-{week}-{_day}" # tokens for ISO 8601 weekdates dt = datetime.strptime(date_string, "%G-%V-%u") @@ -750,7 +750,7 @@ def _build_datetime(parts: _Parts) -> datetime: "Month component is not allowed with the DDD and DDDD tokens." ) - date_string = f"{_year}-{day_of_year}" + date_string = f"{_year:04d}-{day_of_year}" try: dt = datetime.strptime(date_string, "%Y-%j") except ValueError: diff --git a/tests/test_parser.py b/tests/test_parser.py index 7038d880f..4fba59c2d 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -716,6 +716,20 @@ def test_parse_HH_24(self): with pytest.raises(ParserError): self.parser.parse("2019-12-31T24:00:00.999999", "YYYY-MM-DDTHH:mm:ss.S") + @pytest.mark.parametrize("year", [1, 4, 12, 99, 400, 999, 1000, 2024]) + @pytest.mark.parametrize("token", ["DDD", "DDDD"]) + def test_parse_low_year_ordinal(self, year, token): + ordinal = "2" if token == "DDD" else "002" + value = f"{year:04d}-{ordinal}" + assert self.parser.parse(value, f"YYYY-{token}") == datetime(year, 1, 2) + + @pytest.mark.parametrize("year", [1, 4, 12, 99, 400, 999, 1000, 2024]) + def test_parse_low_year_iso_week(self, year): + value = f"{year:04d}-W01-1" + expected = datetime.fromisocalendar(year, 1, 1) + assert self.parser.parse(value, "W") == expected + assert arrow.get(value) == arrow.Arrow.fromdatetime(expected) + def test_parse_W(self): assert self.parser.parse("2011-W05-4", "W") == datetime(2011, 2, 3) assert self.parser.parse("2011W054", "W") == datetime(2011, 2, 3)