Skip to content

Fix dehumanize() silently ignoring negative time values#1279

Open
amanv0007 wants to merge 1 commit into
arrow-py:masterfrom
amanv0007:fix-dehumanize-negative-values
Open

Fix dehumanize() silently ignoring negative time values#1279
amanv0007 wants to merge 1 commit into
arrow-py:masterfrom
amanv0007:fix-dehumanize-negative-values

Conversation

@amanv0007
Copy link
Copy Markdown

Fixes #1278

Problem

dehumanize("in -1 hours") silently returns the same result as dehumanize("in 1 hours") - it drops the minus sign without any warning.

I ran into this while building a scheduling tool that accepts relative time strings from users. A typo like "in -2 days" would silently schedule something 2 days ahead instead of raising an error, which took me a while to track down.

Root cause

The number-extraction regex in dehumanize() uses \d+ to match the numeric value from the input. Since \d only matches [0-9], the minus sign in -1 is never captured - the regex matches 1 and moves on. The sign information is completely lost.

Before this fix

>>> now = arrow.now()
>>> r1 = now.dehumanize("in 1 hours")
>>> r2 = now.dehumanize("in -1 hours")
>>> (r1 - now).total_seconds()
3600.0
>>> (r2 - now).total_seconds()
3600.0  # <- wrong, same as positive!

After this fix

>>> now.dehumanize("in -1 hours")
ValueError: Negative time values are not supported in dehumanize
(got 'in -1 hours'). Use a positive value with 'ago' or 'in' to
indicate direction.

Changes

  • arrow/arrow.py: Added an early check in dehumanize() that detects negative numbers (-\d pattern) in the input string and raises a ValueError with a clear message, before the regex-based parsing begins.
    • tests/test_arrow.py: Added test_negative_values to verify that inputs like "in -1 hours", "in -2 days", "-3 minutes ago", and "in -30 seconds" all raise ValueError.
      All existing dehumanize tests continue to pass.

Copilot AI review requested due to automatic review settings May 17, 2026 17:35
@codecov
Copy link
Copy Markdown

codecov Bot commented May 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (2224255) to head (a345b27).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #1279   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           10        10           
  Lines         2315      2317    +2     
  Branches       358       359    +1     
=========================================
+ Hits          2315      2317    +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds an early-rejection check in Arrow.dehumanize so that inputs containing negative numbers (e.g. "in -1 hours") raise ValueError instead of silently producing a wrongly-signed result (issue #1278).

Changes:

  • Add a regex check at the start of dehumanize that raises ValueError when the input contains a negative number.
  • Add a unit test verifying the new behavior across a few representative inputs.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
arrow/arrow.py Adds the negative-number guard with a descriptive ValueError in dehumanize.
tests/test_arrow.py Adds test_negative_values covering several negative-number inputs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread arrow/arrow.py Outdated
Comment on lines +1388 to +1393
if re.search(r"-\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."
)
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.

Thank you for the excellent suggestion! I have refined the regex check to r"(?:^|\s)-\d" so it is anchored to start-of-string or whitespace and won't trigger false positives on hyphen-joined strings in localized non-English timeframes. Pushed the update!

Comment thread tests/test_arrow.py
Comment on lines +2990 to +3001
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",
]
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!

@amanv0007 amanv0007 force-pushed the fix-dehumanize-negative-values branch from 79847b2 to aaf224e Compare May 17, 2026 17:38
@amanv0007 amanv0007 force-pushed the fix-dehumanize-negative-values branch from aaf224e to a345b27 Compare May 17, 2026 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dehumanize() silently ignores negative time values, returning wrong results

2 participants