diff --git a/arrow/arrow.py b/arrow/arrow.py index eecf23266..4249755fd 100644 --- a/arrow/arrow.py +++ b/arrow/arrow.py @@ -1414,6 +1414,15 @@ def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow": pattern = re.compile(rf"(^|\b|\d){search_string}") match = pattern.search(input_string) + # Singular forms like "a day" have no {0} placeholder, so the + # primary pattern never matches "1 day". Try a numeric form + # using the unit key (e.g. r"\d+\s+day\b") as a fallback. + if not match and "{0}" not in str(time_string): + alt_pattern = re.compile( + rf"(^|\b)\d+\s+{re.escape(str(time_delta))}\b" + ) + match = alt_pattern.search(input_string) + # If there is no match continue to next iteration if not match: continue diff --git a/tests/test_arrow.py b/tests/test_arrow.py index b595e4e21..4cf8f7568 100644 --- a/tests/test_arrow.py +++ b/tests/test_arrow.py @@ -2987,6 +2987,19 @@ def test_czech_slovak(self): assert arw.dehumanize(past_string, locale=lang) == past assert arw.dehumanize(future_string, locale=lang) == future + def test_singular_with_number(self): + # "1 day ago" must work the same as "a day ago" (issue #1150) + arw = arrow.Arrow(2021, 4, 20, 22, 27, 34) + assert arw.dehumanize("1 second ago") == arw.shift(seconds=-1) + assert arw.dehumanize("1 minute ago") == arw.shift(minutes=-1) + assert arw.dehumanize("1 hour ago") == arw.shift(hours=-1) + assert arw.dehumanize("1 day ago") == arw.shift(days=-1) + assert arw.dehumanize("1 week ago") == arw.shift(weeks=-1) + assert arw.dehumanize("1 month ago") == arw.shift(months=-1) + assert arw.dehumanize("1 year ago") == arw.shift(years=-1) + assert arw.dehumanize("in 1 day") == arw.shift(days=1) + assert arw.dehumanize("in 1 week") == arw.shift(weeks=1) + class TestArrowIsBetween: def test_start_before_end(self):