Skip to content

DEP: Deprecate 'generic' unit in np.timedelta64 - #29619

Merged
seberg merged 12 commits into
numpy:mainfrom
riku-sakamoto:enhancement/raise_warning_when_generic_unit_casting
Mar 29, 2026
Merged

DEP: Deprecate 'generic' unit in np.timedelta64#29619
seberg merged 12 commits into
numpy:mainfrom
riku-sakamoto:enhancement/raise_warning_when_generic_unit_casting

Conversation

@riku-sakamoto

@riku-sakamoto riku-sakamoto commented Aug 23, 2025

Copy link
Copy Markdown
Contributor

This PR deprecates the generic unit in np.timedelta64. Using this unit can lead to unexpected behavior in some cases (see #28287 for details). Using generic unit now raises a DeprecationWarning.

  • Allowed behavior (no warning):
import numpy as np

np.timedelta64(10, 's')  # seconds
np.timedelta64("NaT", "ns") # NaT is also created with unit
  • Deprecated behavior (raises FutureWarning):
import numpy as np

np.timedelta64(10)  # generic unit
np.timedellta64("NaT") # NaT without generic unit is not allowed
np.timedelta64(10, 's') + 5 # adding integer to timedelta with generic unit

Changes

Main

  • Raise DeprecationWarning when np.timedelta64 is constructed with the generic unit.
  • Add tests to ensure the warning is raised in relevant scenarios.
  • Add Release notes
  • Improve not to raise the warning in np.ones and np.ones_like .

Test

Test updates fall into three categories.

  • Suppressing the warning in tests where the generic unit seems to be used intentionally. (with pytest.warns(DeprecationWarning))

  • Adding tests to check generic unit's behavior. Some tests uses generic timedelta in pytest.mark.parametrize. In such cases, the warnings cannot be suppressed with pytest.mark.filterwarnings. Instead, this PR add additional tests to check only generic unit's behavior.

  • Modifying tests to use an explicit unit instead of generic.

Future follow up items

  • np.timedelta64() creates a generic timedelta with value 0. We may want to change this to create a timedelta with an explicit unit (e.g., np.timedelta64(0, 's')) instead.

  • np.ones_like now raises DeprecationWarning when the input array is of timedelta type. Resolved

  • np.all_close now raises DeprecationWarning when the input arrays are timedelta type. Resolved

@riku-sakamoto
riku-sakamoto marked this pull request as ready for review August 23, 2025 10:30
Comment thread pytest.ini Outdated
# Ignore DeprecationWarning from typing.mypy_plugin
ignore:`numpy.typing.mypy_plugin` is deprecated:DeprecationWarning
# Ignore Runtime Warning from datetime by calculating unitless value and unitful value
ignore:Casting from unitless timedelta to unitful timedelta is ambiguous.:RuntimeWarning

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I believe that if we do this, we'd likely want at least one test case that actually makes sure that the warning is issued.

I see locally that there are 18 failures if this is removed though, and we wouldn't want 18 checks for the warning. Still, it might be nice if we could suppress most of them but enforce at least one of them.

That said, the discussion in the matching issue suggests that the decision here may be tricky, so it may be best to wait for some design feedback first before making changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@tylerjereddy

Thank you for the feedback!
I agree that adding a test case to check this warning makes sense.
As you suggested, I’ll wait for the design feedback before making the change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

According to the issue discussion and the triage meeting, deprecation of the np.generic unit has been decided. I have updated the test implementation as you suggested.

I would appreciate it if you could take a look.

@charris charris added the 56 - Needs Release Note. Needs an entry in doc/release/upcoming_changes label Sep 1, 2025
@charris

charris commented Sep 1, 2025

Copy link
Copy Markdown
Member

Needs a release note.

@riku-sakamoto
riku-sakamoto force-pushed the enhancement/raise_warning_when_generic_unit_casting branch 2 times, most recently from 7b3b00a to 902f4ac Compare September 7, 2025 11:42
@riku-sakamoto
riku-sakamoto force-pushed the enhancement/raise_warning_when_generic_unit_casting branch 2 times, most recently from 93ae278 to 9e14d71 Compare September 7, 2025 21:28
@riku-sakamoto riku-sakamoto changed the title ENH: Raise RuntimeWarning when casting from a unitless np.timedelta64 to unitful one. DEP: Deprecate 'generic' unit in np.timedelta64 and np.datetime64 Sep 7, 2025
@riku-sakamoto

riku-sakamoto commented Sep 24, 2025

Copy link
Copy Markdown
Contributor Author

Needs a release note.

@charris
I've added the release note. Thank you for the review!

@seberg

seberg commented Oct 15, 2025

Copy link
Copy Markdown
Member

@jbrockmendel I wonder if you have thoughts on this. I think the idea now was to deprecate any unitless scalars except for NaT (I suppose 0 may be another plausible exception).

The hope would be that we may still need NaT as a unitless scalar, but overall try to make it hard or impossible to work with this.

I think the scalar trick may well be good. But we may need some deeper stuff to really disable this fully. Since I think you can still cast from int (or view), etc.

(But maybe it can be a follow-up too, I am mostly curious if it seems safe to remove almost all unitless datetimes from a pandas perspective.)

@jbrockmendel

Copy link
Copy Markdown
Contributor

I am mostly curious if it seems safe to remove almost all unitless datetimes from a pandas perspective

That won't cause us any problems, might even allow us to clean up some checking-for-it code.

Comment thread numpy/_core/tests/test_cython.py Outdated
sys.path.append(str(build_dir))


@pytest.mark.filterwarnings("ignore::FutureWarning")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Rather than a general filter, could you assert that the warning is raised when expected

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the comment! I've updated the test to assert that the warning is raised when expected.

pytest.mark.filterwarnings is now used only in numpy/typing/tests/test_typing.py to avoid failures when this test loads a Python script file that uses the generic unit. I can update it further if needed.

Comment thread numpy/_core/tests/test_datetime.py Outdated
# # m8 generic units
# (np.timedelta64(1890),
# np.timedelta64(31),
# 60),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a test in test_deprecations that asserts that these calls now warn?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes! I've implemented it as test_generic_timedelta_floor_divide in test_datetime.py.

Comment thread numpy/_core/tests/test_datetime.py Outdated
def test_raise_warning_for_timedelta_with_generic_unit(self, value: int):
msg = "Using 'generic' unit for NumPy timedelta is deprecated"
with pytest.warns(FutureWarning, match=msg):
_ = np.timedelta64(value)

@mattip mattip Oct 30, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this test these tests should be moved to test_deprecations

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've moved the relevant tests to test_deprecations.py.

@riku-sakamoto
riku-sakamoto force-pushed the enhancement/raise_warning_when_generic_unit_casting branch 3 times, most recently from 91b812e to acbcdf2 Compare October 31, 2025 19:11
@riku-sakamoto

riku-sakamoto commented Oct 31, 2025

Copy link
Copy Markdown
Contributor Author

It seems that some CI jobs are failing (especially those related to Python 3.11). I’m investigating it now.

Update: I've resolved them.

@riku-sakamoto
riku-sakamoto force-pushed the enhancement/raise_warning_when_generic_unit_casting branch 5 times, most recently from 2a42032 to c943f3a Compare November 2, 2025 06:08
@seberg seberg modified the milestone: 2.4.0 release Nov 4, 2025
@riku-sakamoto

Copy link
Copy Markdown
Contributor Author

@seberg
It sounds like pandas is fine with removing all unitless timedeltas.
In that case, should we also emit a warning when NaT is created in a unitless form, so that we can deprecate it as well in the future?

@seberg

seberg commented Nov 20, 2025

Copy link
Copy Markdown
Member

@riku-sakamoto yes, since pandas is likely fine, I think we can give it a shot. But we need to wait another few weeks until branching unfortunatley.
(And actually if we merge it just after branching, it'll confuse a bit of downstream also, because they may think this is included in the pre-release when it's not. But maybe possible to try anyway.)

@riku-sakamoto
riku-sakamoto force-pushed the enhancement/raise_warning_when_generic_unit_casting branch from 7445340 to c43c82d Compare March 7, 2026 07:24
@riku-sakamoto riku-sakamoto changed the title DEP: Deprecate 'generic' unit in np.timedelta64 and np.datetime64 DEP: Deprecate 'generic' unit in np.timedelta64 Mar 7, 2026
@riku-sakamoto

Copy link
Copy Markdown
Contributor Author

Thank you all for the last triage meeting.
I've updated this branch with the following changes.

  • Resolve conflicts with the latest main
  • Avoid raising the warning when calling np.ones for timedelta
  • Avoid raising the warning when calling np.allclose for timedelta
  • Update the release note to mention operations like timedelta_arr + 1

Just to note, the CI failure does not seem to be related to this PR.

@seberg seberg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks, we had discussed this a few times and in general agreed to try this.

I'll ping the mailing list as well. If there is downstream fallout, we should consider reverting this. From pandas perspective this is the right step, but I am not 100% sure if it a painless one either way.
Astropy might also notice it (but they test against nighties well).

In general, removing the ability to mix integers with timedelta/datetimes seems right and this is probably the most gentle first step.

We could even re-instate specific things like arr + 1 e.g. ufuncs and comparisons that mix with integers (or just Python integers).

@seberg seberg removed the 56 - Needs Release Note. Needs an entry in doc/release/upcoming_changes label Mar 29, 2026
@seberg
seberg merged commit feeaad6 into numpy:main Mar 29, 2026
85 checks passed
@riku-sakamoto

Copy link
Copy Markdown
Contributor Author

@seberg Thank you for the review and for merging this!

@seberg

seberg commented Mar 29, 2026

Copy link
Copy Markdown
Member

There is some fallout here. I half think the easiest solution is to change behavior (I guess with another small release note) so that np.dtype("M") actually returns a ns datetime and np.dtype("m") returns a timedelta one.

Rethinking it, there some subtleties. I.e. np.array([np.timedelta64(3, "ns")], dtype="m") needs to keep working the way it currently does.
That is in principle not so hard, but in practice the path it currently takes is still np.dtype("m") -> unitless singleton -> type(uniteless singleton). But if np.dtype("m") there gives a warning, this conversion needs to happen later.

(That should be solvable, in practice there is still a clear path here. Just posting in case you (or someone else) is interested in it. It would be nice to solve this)

@jorenham

Copy link
Copy Markdown
Member

Eh, bit late, but np.timedelta64() isn't emitting a warning right now:

In [1]: np.timedelta64()
Out[1]: np.timedelta64(0)

In [2]: np.timedelta64(0)
<ipython-input-2-8cec810ed165>:1: DeprecationWarning: Using 'generic' unit for NumPy timedelta is deprecated, and will raise an error in the future. Please use a specific units instead.
  np.timedelta64(0)
Out[2]: np.timedelta64(0)

@jorenham

Copy link
Copy Markdown
Member

The warning for adding integers to a unit-full timedelta64 is also a bit confusing I think:

In [2]: np.timedelta64(1, "s") + 1
<ipython-input-2-cefd7f046fa9>:1: DeprecationWarning: Using 'generic' unit for NumPy timedelta is deprecated, and will raise an error in the future. Please use a specific units instead.
  np.timedelta64(1, "s") + 1
Out[2]: np.timedelta64(2,'s')

It might be confusing because np.timedelta64(1, "s") + 1 does not explicitly construct a unitless timedelta64. Not everyone will know that the 1 here is an implicit timedelta64(1). Then you wouldn't know that the "generic unit" refers to the RHS 1 instead of the LHS np.timedelta64(1, "s"). As in: "I specified a unit for the timedelta64, so what's the problem?".

@seberg

seberg commented Mar 29, 2026

Copy link
Copy Markdown
Member

Hmmm, maybe we could ammend the warning message to mention it? That part could be changed, but it would remove a lot of the point, adding special paths for this feels a bit much maybe.

One thing I am not sure about is, if you were to change the default to ns for np.dtype("m") then some things might change behavior without a warning.

@riku-sakamoto

Copy link
Copy Markdown
Contributor Author

Thanks for the feedback. @seberg @jorenham

I’ve opened a follow-up issue to discuss the default behavior of np.timedelta64 and np.datetime64:
#31103 to track this topic.
As you suggested, it would be good to gather more opinions before deciding on the behavior.

Regarding the warning message, I can also open a separate issue if needed.
It might be sufficient to improve the current warning message.
For example, just adding "bare integer is also treated as generic unit and will raise this warning." .

@jorenham

Copy link
Copy Markdown
Member

It might be sufficient to improve the current warning message.
For example, just adding "bare integer is also treated as generic unit and will raise this warning." .

sure, sounds fine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

07 - Deprecation triage review Issue/PR to be discussed at the next triage meeting

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants