From 315e396b35cf131df1b8df15144fe2d60aa6d74a Mon Sep 17 00:00:00 2001 From: Serhii A Date: Thu, 23 Jul 2026 14:34:36 +0200 Subject: [PATCH] Fix ISO8601 parsing with explicit languages (#1352) Close #360 --- dateparser/parser.py | 18 +++++++++++++++++- tests/test_date_parser.py | 26 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/dateparser/parser.py b/dateparser/parser.py index 54bde2ceb..1f56515fc 100644 --- a/dateparser/parser.py +++ b/dateparser/parser.py @@ -633,7 +633,23 @@ def set_and_return(token, type, component, dateobj, skip_date_order=False): def parse_number(token, skip_component=None): type = 0 - for component, directives in self.ordered_num_directives.items(): + num_directives = self.ordered_num_directives + if ( + skip_component == "year" + and self.day is None + and self.month is None + and "DATE_ORDER" not in self.settings._mod_settings + ): + # The date string starts with a four-digit year (e.g. an + # ISO 8601 date like "2017-06-22"), so the remaining numeric + # components are expected in month-day order, regardless of + # the locale date order, unless the caller explicitly set + # DATE_ORDER (#360). + num_directives = { + k: self.num_directives[k] for k in ("month", "day", "year") + } + + for component, directives in num_directives.items(): if skip_component == component: continue for directive in directives: diff --git a/tests/test_date_parser.py b/tests/test_date_parser.py index 4bbf36c55..012c8a956 100644 --- a/tests/test_date_parser.py +++ b/tests/test_date_parser.py @@ -929,6 +929,32 @@ def test_iso_datestamp_format_should_always_parse( self.result["date_obj"] = self.result["date_obj"].replace(tzinfo=None) self.then_date_obj_exactly_is(expected) + @parameterized.expand( + [ + param("2017-06-22", languages=["it"], expected=datetime(2017, 6, 22)), + param("2017-06-10", languages=["it"], expected=datetime(2017, 6, 10)), + param("2017-06-22", languages=["fr"], expected=datetime(2017, 6, 22)), + param( + "2015-05-02T10:20:19+0000", + languages=["fr"], + expected=datetime(2015, 5, 2, 10, 20, 19), + ), + ] + ) + def test_iso_datestamp_format_should_parse_with_locale_date_order( + self, date_string, languages, expected + ): + # Regression test for #360: dates starting with a four-digit year + # (e.g. ISO 8601 dates) must parse even when the locale date order + # is not year-first (Italian and French use DMY), without needing + # the PREFER_LOCALE_DATE_ORDER=False workaround. + self.given_local_tz_offset(0) + self.given_parser(languages=languages) + self.when_date_is_parsed(date_string) + self.then_date_was_parsed_by_date_parser() + self.result["date_obj"] = self.result["date_obj"].replace(tzinfo=None) + self.then_date_obj_exactly_is(expected) + @parameterized.expand( [ # Epoch timestamps.