From 541d263c13a59ce60ff8996f15ff9a6829c9e4d7 Mon Sep 17 00:00:00 2001 From: Shashwat Agrawal Date: Sun, 9 Feb 2025 14:22:58 +0530 Subject: [PATCH 1/3] fix: incorrect ISO week 53 conversion when only 52 weeks exist --- pandas/_libs/tslibs/strptime.pyx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pandas/_libs/tslibs/strptime.pyx b/pandas/_libs/tslibs/strptime.pyx index ed784b6f5ab22..fb89f1328529d 100644 --- a/pandas/_libs/tslibs/strptime.pyx +++ b/pandas/_libs/tslibs/strptime.pyx @@ -924,6 +924,13 @@ cdef (int, int) _calc_julian_from_V(int iso_year, int iso_week, int iso_weekday) correction = date(iso_year, 1, 4).isoweekday() + 3 ordinal = (iso_week * 7) + iso_weekday - correction + + if iso_week == 53: + now = date.fromordinal(date(iso_year, 1, 1).toordinal() + ordinal - iso_weekday) + jan_4th = date(iso_year+1, 1, 4) + if (jan_4th - now).days < 7: + raise ValueError(f"Week 53 does not exist in ISO year {iso_year}.") + # ordinal may be negative or 0 now, which means the date is in the previous # calendar year if ordinal < 1: From 1899aacaa1c40e7dfad13c020cded000fdcef4ca Mon Sep 17 00:00:00 2001 From: Shashwat Agrawal Date: Tue, 11 Feb 2025 11:56:39 +0530 Subject: [PATCH 2/3] test(invalid_iso_week): ready, set, go! --- pandas/tests/tools/test_to_datetime.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pandas/tests/tools/test_to_datetime.py b/pandas/tests/tools/test_to_datetime.py index 566fd8d901569..5bfcae9010559 100644 --- a/pandas/tests/tools/test_to_datetime.py +++ b/pandas/tests/tools/test_to_datetime.py @@ -794,12 +794,37 @@ def test_to_datetime_np_str(self): ["2015-1-1", "%G-%V-%u", datetime(2014, 12, 29, 0, 0)], ["2015-1-4", "%G-%V-%u", datetime(2015, 1, 1, 0, 0)], ["2015-1-7", "%G-%V-%u", datetime(2015, 1, 4, 0, 0)], + ["2024-52-1", "%G-%V-%u", datetime(2024, 12, 23, 0, 0)], + ["2024-52-7", "%G-%V-%u", datetime(2024, 12, 29, 0, 0)], + ["2025-1-1", "%G-%V-%u", datetime(2024, 12, 30, 0, 0)], + ["2020-53-1", "%G-%V-%u", datetime(2020, 12, 28, 0, 0)], ], ) def test_to_datetime_iso_week_year_format(self, s, _format, dt): # See GH#16607 assert to_datetime(s, format=_format) == dt + @pytest.mark.parametrize( + "msg, s, _format", + [ + [ + "Week 53 does not exist in ISO year 2024", + "2024 53 1", + "%G %V %u", + ], + [ + "Week 53 does not exist in ISO year 2023", + "2023 53 1", + "%G %V %u", + ], + ], + ) + @pytest.mark.parametrize("errors", ["raise"]) + def test_invalid_iso_week_53(self, msg, s, _format, errors): + # See GH#60885 + with pytest.raises(ValueError, match=msg): + to_datetime(s, format=_format, errors=errors) + @pytest.mark.parametrize( "msg, s, _format", [ From ecf0e4ca15bae8228acd47d2af6456825b285eb5 Mon Sep 17 00:00:00 2001 From: Shashwat Agrawal Date: Tue, 11 Feb 2025 22:39:03 +0530 Subject: [PATCH 3/3] test: removing unwanted errors="raise" as those are the defaults. --- pandas/tests/tools/test_to_datetime.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pandas/tests/tools/test_to_datetime.py b/pandas/tests/tools/test_to_datetime.py index 5bfcae9010559..e039f54960389 100644 --- a/pandas/tests/tools/test_to_datetime.py +++ b/pandas/tests/tools/test_to_datetime.py @@ -819,11 +819,10 @@ def test_to_datetime_iso_week_year_format(self, s, _format, dt): ], ], ) - @pytest.mark.parametrize("errors", ["raise"]) - def test_invalid_iso_week_53(self, msg, s, _format, errors): + def test_invalid_iso_week_53(self, msg, s, _format): # See GH#60885 with pytest.raises(ValueError, match=msg): - to_datetime(s, format=_format, errors=errors) + to_datetime(s, format=_format) @pytest.mark.parametrize( "msg, s, _format",