diff --git a/dateparser/freshness_date_parser.py b/dateparser/freshness_date_parser.py index 0780bb89a..b1b8f4df3 100644 --- a/dateparser/freshness_date_parser.py +++ b/dateparser/freshness_date_parser.py @@ -30,9 +30,16 @@ class FreshnessDateDataParser: """Parses date string like "1 year, 2 months ago" and "3 hours, 50 minutes ago".""" - def _are_all_words_units(self, date_string: str) -> bool: - skip = [_UNITS, r"ago|in|\d+", r":|[ap]m"] - + def _are_all_words_units(self, date_string: str, has_time: bool) -> bool: + skip = [_UNITS, r"ago|in", r":|[ap]m"] + if has_time: + skip.append(r"\d+") + + matches = list(PATTERN.finditer(date_string)) + if matches: + end = matches[-1].end() + date_string = date_string[:end] + re.sub(r"\d+", "", date_string[end:]) + date_string = PATTERN.sub("", date_string) date_string = re.sub(r"\s+", " ", date_string.strip()) words = [x for x in re.split(r"\W", date_string) if x] @@ -101,7 +108,7 @@ def apply_time(dateobj: datetime, timeobj: time | None) -> datetime: now = datetime.now(self.get_local_tz()) date, period, parts = self._parse_date( - date_string, now, settings.PREFER_DATES_FROM + date_string, now, settings.PREFER_DATES_FROM, _time is not None ) if date and day is not None: @@ -139,9 +146,13 @@ def apply_time(dateobj: datetime, timeobj: time | None) -> datetime: return date, period, parts def _parse_date( # noqa: PLR0912 - self, date_string: str, now: datetime, prefer_dates_from: str + self, + date_string: str, + now: datetime, + prefer_dates_from: str, + has_time: bool, ) -> tuple[datetime, str, tuple[str, ...]] | tuple[None, None, tuple[()]]: - if not self._are_all_words_units(date_string): + if not self._are_all_words_units(date_string, has_time): return None, None, () result = self.get_kwargs(date_string) diff --git a/tests/test_freshness_date_parser.py b/tests/test_freshness_date_parser.py index c6a596ac4..274389682 100644 --- a/tests/test_freshness_date_parser.py +++ b/tests/test_freshness_date_parser.py @@ -72,6 +72,8 @@ def test_relative_past_dates_with_time_as_period( param("last decade", ago={"years": 10}, period="year"), param("a decade ago", ago={"years": 10}, period="year"), param("100 decades", ago={"years": 1000}, period="year"), + param("3 days ago 15", ago={"days": 3}, period="day"), + param("yesterday at 5", ago={"days": 1}, period="day"), # Regression tests for #1304: an explicit sign on a component is # preserved when ``decades`` is folded into ``years`` instead of # being overwritten by the decade's sign. Unsigned components still