Skip to content

ENH: raise OverflowError on timedelta64 float multiply/divide overflow#31979

Open
jbrockmendel wants to merge 1 commit into
numpy:mainfrom
jbrockmendel:bug-td64-float
Open

ENH: raise OverflowError on timedelta64 float multiply/divide overflow#31979
jbrockmendel wants to merge 1 commit into
numpy:mainfrom
jbrockmendel:bug-td64-float

Conversation

@jbrockmendel

@jbrockmendel jbrockmendel commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Human here: @seberg as with my other recent PRs, acknowledging this is mostly claude. This is porting pandas-dev/pandas#65515

Claude below the line


Follow-up to GH-31378, which made datetime64/timedelta64 add, subtract, and integer-multiply raise OverflowError on int64 overflow instead of silently wrapping. This extends the same guarantee to the float multiply and divide loops, which previously cast the float64 result straight to int64 and silently saturated (or landed on the NaT sentinel) when the value exceeded int64 range.

What changes

TIMEDELTA_md_m_multiply (td * float), TIMEDELTA_dm_m_multiply (float * td), and TIMEDELTA_md_m_divide (td / float, which also backs td // float) now raise OverflowError when the result would overflow int64:

>>> np.timedelta64(2**62, "s") * 2.5      # was: silently wrapped
OverflowError: Overflow in timedelta64 * float64 multiplication
>>> np.timedelta64(2**62, "s") / 0.4      # was: silently wrapped
OverflowError: Overflow in timedelta64 / float64 division

A shared timedelta_from_double helper maps a NaN result to NaT and treats any magnitude >= 2**63 (finite overflow or ±inf) as overflow. The bound is 2**63 rather than int64.max, because 2**63 - 1 is not exactly representable in float64 and rounds up to 2**63; a result landing there would otherwise slip past the check and saturate on the cast (and -2**63 is itself the NaT sentinel).

Preserved (non-overflow) behavior

A NaN operand, 0 * inf, division by zero, and division by infinity still yield NaT (or zero), matching the pre-existing convention:

>>> np.timedelta64(5, "s") / 0.0          # NaT, not an error
>>> np.timedelta64(5, "s") / np.float64(np.inf)   # 0 seconds
>>> np.timedelta64(5, "s") * np.float64(np.nan)   # NaT

The one intentional behavior change to an existing test: timedelta64(nonzero) * inf now raises instead of returning NaT.

🤖 Generated with Claude Code

Multiplying or dividing a timedelta64 by a float previously cast the
float64 result straight to int64, silently saturating (or landing on the
NaT sentinel) when the value exceeded int64 range. Detect that in the
TIMEDELTA_md_m_multiply, TIMEDELTA_dm_m_multiply and TIMEDELTA_md_m_divide
loops and raise OverflowError instead, mirroring the integer
multiply/add/subtract loops (numpy numpyGH-31378).

A shared timedelta_from_double helper maps a NaN result to NaT and reports
any magnitude >= 2**63 (finite overflow or +/-inf) as overflow; the bound
is 2**63 rather than int64.max because 2**63 - 1 is not representable in
float64. Special cases are preserved: a NaN operand, 0 * inf, division by
zero, and division by infinity still yield NaT (or zero) rather than
raising.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jorenham

Copy link
Copy Markdown
Member

sorry but this goes against the AI policy

@jbrockmendel

Copy link
Copy Markdown
Contributor Author

Fair enough. You closed while I was in the process of updating the comment with the ping to seberg acknowledging the AI use.

@jorenham

Copy link
Copy Markdown
Member

Ah ok, that changes things

@jorenham jorenham reopened this Jul 12, 2026
@jorenham

Copy link
Copy Markdown
Member

I'm still not sure how I feel about Claude as co-author though.

@ngoldbaum

Copy link
Copy Markdown
Member

I'm still not sure how I feel about Claude as co-author though.

IMO it's mostly advertising for anthropic but it shouldn't stop us from accepting the code. AI-generated code will get in either way.

@ngoldbaum

Copy link
Copy Markdown
Member

Also sorry for the drive-by comment, I think improvements like this are great and I'll try to get it reviewed.

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.

3 participants