Skip to content
Open
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
12 changes: 12 additions & 0 deletions arrow/arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,18 @@ def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow":

current_time = self.fromdatetime(self._datetime)

# Reject negative time values early. The number-extraction regex
# (\d+) only matches unsigned digits, so an input like "in -1 hours"
# would silently drop the minus sign and return the *opposite*
# direction. Raising here gives the caller a clear message instead
# of a quietly wrong result.
if re.search(r"(?:^|\s)-\d", input_string):
raise ValueError(
f"Negative time values are not supported in dehumanize "
f"(got {input_string!r}). "
f"Use a positive value with 'ago' or 'in' to indicate direction."
)

# Create an object containing the relative time info
time_object_info = dict.fromkeys(
["seconds", "minutes", "hours", "days", "weeks", "months", "years"], 0
Expand Down
27 changes: 27 additions & 0 deletions tests/test_arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2987,6 +2987,33 @@ def test_czech_slovak(self):
assert arw.dehumanize(past_string, locale=lang) == past
assert arw.dehumanize(future_string, locale=lang) == future

def test_negative_values(self):
arw = arrow.Arrow(2000, 6, 18, 5, 55, 0)

# Negative time values should raise ValueError instead of
# silently dropping the sign and returning a wrong result.
# See: https://github.com/arrow-py/arrow/issues/1278
negative_inputs = [
"in -1 hours",
"in -2 days",
"-3 minutes ago",
"in -30 seconds",
]
Comment on lines +2990 to +3001
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I've added a non-negative test ensuring "in 1 hours" and "2 days ago" succeed, and verified that hyphenated strings without preceding spaces (like "some-2nd-hour") bypass the negative check as expected. Pushed the update!


for s in negative_inputs:
with pytest.raises(ValueError, match="Negative time values"):
arw.dehumanize(s)

# Positive time values should continue to succeed
assert arw.dehumanize("in 1 hours") == arw.shift(hours=1)
assert arw.dehumanize("2 days ago") == arw.shift(days=-2)

# Hyphenated strings without spaces preceding the minus/hyphen should not
# trigger the negative validation error (they will raise ValueError for unrecognized units).
with pytest.raises(ValueError) as excinfo:
arw.dehumanize("some-2nd-hour")
assert "Negative time values" not in str(excinfo.value)


class TestArrowIsBetween:
def test_start_before_end(self):
Expand Down
Loading