diff --git a/arrow/parser.py b/arrow/parser.py index fc3774b09..c44b5fef6 100644 --- a/arrow/parser.py +++ b/arrow/parser.py @@ -713,10 +713,7 @@ def _build_datetime(parts: _Parts) -> datetime: # day not given, default to 1 _day = 1 - date_string = f"{year}-{week}-{_day}" - - # tokens for ISO 8601 weekdates - dt = datetime.strptime(date_string, "%G-%V-%u") + dt = datetime.fromisocalendar(year, week, _day) parts["year"] = dt.year parts["month"] = dt.month diff --git a/arrow/util.py b/arrow/util.py index 7171d92cc..ea4a2fb53 100644 --- a/arrow/util.py +++ b/arrow/util.py @@ -95,13 +95,7 @@ def iso_to_gregorian(iso_year: int, iso_week: int, iso_day: int) -> datetime.dat if not 1 <= iso_day <= 7: raise ValueError("ISO Calendar day value must be between 1-7") - # The first week of the year always contains 4 Jan. - fourth_jan = datetime.date(iso_year, 1, 4) - delta = datetime.timedelta(fourth_jan.isoweekday() - 1) - year_start = fourth_jan - delta - gregorian = year_start + datetime.timedelta(days=iso_day - 1, weeks=iso_week - 1) - - return gregorian + return datetime.date.fromisocalendar(iso_year, iso_week, iso_day) def validate_bounds(bounds: str) -> None: diff --git a/tests/test_factory.py b/tests/test_factory.py index 056cee412..b1981ca86 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -236,6 +236,11 @@ def test_one_arg_iso_calendar(self): with pytest.raises(ValueError): self.factory.get((2014, 7, 10)) + @pytest.mark.parametrize("year", [2014, 2019, 2021]) + def test_one_arg_iso_calendar_invalid_week(self, year): + with pytest.raises(ValueError): + self.factory.get((year, 53, 1)) + def test_one_arg_other(self): with pytest.raises(TypeError): self.factory.get(object()) diff --git a/tests/test_parser.py b/tests/test_parser.py index 7038d880f..9b0c61491 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -752,6 +752,22 @@ def test_parse_W(self): with pytest.raises(ParserError): self.parser.parse(fmt, "W") + @pytest.mark.parametrize( + "value, expected", + [ + ("0001-W01-1", datetime(1, 1, 1)), + ("0099-W01-1", datetime(98, 12, 29)), + ("0999-W01-1", datetime(998, 12, 31)), + ], + ) + def test_parse_W_early_year(self, value, expected): + assert self.parser.parse(value, "W") == expected + + @pytest.mark.parametrize("year", [2014, 2019, 2021]) + def test_parse_W_invalid_week(self, year): + with pytest.raises(ValueError): + self.parser.parse(f"{year}-W53-1", "W") + def test_parse_normalize_whitespace(self): assert self.parser.parse( "Jun 1 2005 1:33PM", "MMM D YYYY H:mmA", normalize_whitespace=True