Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 39 additions & 17 deletions dateparser/date.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,26 +275,48 @@ def _try_nospaces_parser(self):
return self._try_parser(parse_method=_parse_nospaces)

def _try_parser(self, parse_method):
_order = self._settings.DATE_ORDER
original_order = self._settings.DATE_ORDER

# Use locale date order unless DATE_ORDER was explicitly set by the caller.
if (
self._settings.PREFER_LOCALE_DATE_ORDER
and "DATE_ORDER" not in self._settings._mod_settings
):
first_order = self.locale.info.get("date_order", original_order)
else:
first_order = original_order

candidates = [first_order]

# If the caller requires a year (and not a day) and did not set DATE_ORDER,
# retry once or twice with year-biased orders to resolve month-number ambiguity.
require_parts = set(getattr(self._settings, "REQUIRE_PARTS", None) or [])
if (
"DATE_ORDER" not in self._settings._mod_settings
and "year" in require_parts
and "day" not in require_parts
):
for order in ("MYD", "YMD"):
if order not in candidates:
candidates.append(order)

translated = self._get_translated_date()

try:
if self._settings.PREFER_LOCALE_DATE_ORDER:
if "DATE_ORDER" not in self._settings._mod_settings:
self._settings.DATE_ORDER = self.locale.info.get(
"date_order", _order
for order in candidates:
self._settings.DATE_ORDER = order
try:
date_obj, period = date_parser.parse(
translated,
parse_method=parse_method,
settings=self._settings,
)
date_obj, period = date_parser.parse(
self._get_translated_date(),
parse_method=parse_method,
settings=self._settings,
)
self._settings.DATE_ORDER = _order
return DateData(
date_obj=date_obj,
period=period,
)
except ValueError:
self._settings.DATE_ORDER = _order
return DateData(date_obj=date_obj, period=period)
except ValueError:
continue
return None
finally:
self._settings.DATE_ORDER = original_order

def _try_given_formats(self):
if not self.date_formats:
Expand Down
47 changes: 47 additions & 0 deletions tests/test_clean_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,53 @@ def test_dates_which_do_not_match_locales_are_not_parsed(
self.when_date_is_parsed(date_string, locales=locales)
self.then_date_was_not_parsed()

@parameterized.expand(
[
param(date_string="Oct-23", expected_date=datetime(2023, 10, 1, 0, 0)),
param(date_string="May-23", expected_date=datetime(2023, 5, 1, 0, 0)),
]
)
def test_require_parts_month_year_parses_month_year(
self, date_string, expected_date
):
# Regression: when year is required, Mon-YY should be interpreted as month-year.
base = datetime(2050, 1, 1, 0, 0)
self.when_date_is_parsed_with_settings(
date_string,
settings={
"RELATIVE_BASE": base,
"PREFER_DAY_OF_MONTH": "first",
"PREFER_DATES_FROM": "past",
"REQUIRE_PARTS": ["month", "year"],
},
)
self.then_parsed_date_and_time_is(expected_date)

def test_require_parts_does_not_override_explicit_date_order(self):
# Explicit DATE_ORDER must be respected.
base = datetime(2050, 1, 1, 0, 0)
self.when_date_is_parsed_with_settings(
"Oct-23",
settings={
"RELATIVE_BASE": base,
"REQUIRE_PARTS": ["month", "year"],
"DATE_ORDER": "MDY",
},
)
self.then_date_was_not_parsed()

def test_require_parts_month_day_parses_month_day(self):
# If day is required, Mon-XX should remain month-day.
base = datetime(2000, 1, 1, 0, 0)
self.when_date_is_parsed_with_settings(
"Oct-23",
settings={
"RELATIVE_BASE": base,
"REQUIRE_PARTS": ["month", "day"],
},
)
self.then_parsed_date_and_time_is(datetime(2000, 10, 23, 0, 0))

def when_date_is_parsed_with_defaults(self, date_string):
self.result = dateparser.parse(date_string)

Expand Down
Loading