From 13efeaca1b8090b20a76b986f73037005ae382ca Mon Sep 17 00:00:00 2001 From: Ben Buzbee Date: Tue, 2 Apr 2024 11:51:20 -0400 Subject: [PATCH] Fix date_parser with prefer_month_of_year wrong results Fix two problems 1. Parser would use current month even if prefer_month_of_year was not current when relative_base was not none 2. Parser would use current month to derive 'what is the last day of this month' - for example, with prefer_month=last and prefer_day=past, but current_month=april, it would return december 30th, because it would use april to find that the last day was the 30th, when it should use the month. Additionally, add a test to test_date_parser that uses prefer_month --- dateparser/parser.py | 11 +++++--- tests/test_date_parser.py | 57 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/dateparser/parser.py b/dateparser/parser.py index 16751188b..3c18c30da 100644 --- a/dateparser/parser.py +++ b/dateparser/parser.py @@ -598,10 +598,11 @@ def _correct_for_month(self, dateobj): relative_base_month = ( relative_base.month if hasattr(relative_base, "month") else relative_base ) - if getattr(self, "_token_month", None) or relative_base_month: + + if getattr(self, "_token_month", None): return dateobj - dateobj = set_correct_month_from_settings(dateobj, self.settings) + dateobj = set_correct_month_from_settings(dateobj, self.settings, relative_base_month) return dateobj @classmethod @@ -613,11 +614,13 @@ def parse(cls, datestring, settings, tz=None): # correction for past, future if applicable dateobj = po._correct_for_time_frame(dateobj, tz) + # correction for preference of month: beginning, current, end + # must happen before day so that day is derived from the correct month + dateobj = po._correct_for_month(dateobj) + # correction for preference of day: beginning, current, end dateobj = po._correct_for_day(dateobj) - # correction for preference of month: beginning, current, end - dateobj = po._correct_for_month(dateobj) period = po._get_period() return dateobj, period diff --git a/tests/test_date_parser.py b/tests/test_date_parser.py index 97ee361cd..67df04712 100644 --- a/tests/test_date_parser.py +++ b/tests/test_date_parser.py @@ -1265,6 +1265,63 @@ def test_prefer_dates_from_with_timezone( self.then_date_was_parsed_by_date_parser() self.then_date_obj_exactly_is(expected) + + @parameterized.expand( + [ + param( + "2015", + prefer_day="current", + prefer_month="current", + today=datetime(2010, 2, 10), + expected=datetime(2015, 2, 10), + ), + param( + "2015", + prefer_day="last", + prefer_month="current", + today=datetime(2010, 2, 10), + expected=datetime(2015, 2, 28), + ), + param( + "2015", + prefer_day="first", + prefer_month="current", + today=datetime(2010, 2, 10), + expected=datetime(2015, 2, 1), + ), + param( + "2015", + prefer_day="current", + prefer_month="last", + today=datetime(2010, 2, 10), + expected=datetime(2015, 12, 10), + ), + param( + "2015", + prefer_day="last", + prefer_month="last", + today=datetime(2010, 2, 10), + expected=datetime(2015, 12, 31), + ), + param( + "2020", #Leap year last day test + prefer_day="last", + prefer_month="current", + today=datetime(2010, 2, 10), + expected=datetime(2020, 2, 29), + ), + ] + ) + def test_dates_with_no_day_or_month( + self, date_string, prefer_day, prefer_month, today=None, expected=None + ): + self.given_parser( + settings={"PREFER_DAY_OF_MONTH": prefer_day, "PREFER_MONTH_OF_YEAR": prefer_month, "RELATIVE_BASE": today} + ) + self.when_date_is_parsed(date_string) + self.then_date_was_parsed_by_date_parser() + self.then_date_obj_exactly_is(expected) + def given_local_tz_offset(self, offset): self.add_patch( patch.object(