Skip to content

BUG: timedelta64 comparison is not transitive #28287

@mdickinson

Description

@mdickinson

Describe the issue:

The logic for timedelta64 comparisons involving a generic timedelta64 is surprising, and leads to non-transitivity of something that I'd expect to be a total ordering. In the snippet below, x < y and y < z are both True, but x < z is False.

>>> import numpy as np
>>> x, y, z = np.timedelta64(1, "ms"), np.timedelta64(2), np.timedelta64(5, "ns")
>>> x < y < z
np.True_
>>> x < z
np.False_

The x < z result is what I expect. For x < y and y < z, I was expecting either a consistent default for the units for y (though I'm not sure what default I was expecting - any of days / seconds / nanoseconds would seem plausible), or to get an error or warning about an ill-defined comparison.

It appears that the actual behaviour is that y is interpreted as being in milliseconds for the x < y comparison, and then in nanoseconds for the y < z comparison.

The same lack of transitivity applies to equality comparisons:

>>> x, y, z = np.timedelta64(1, "ms"), np.timedelta64(1), np.timedelta64(1, "ns")
>>> x == y == z
np.True_
>>> x == z
np.False_

(Though it looks like we're protected from peculiar dict / set containment consequences by the fact that y isn't hashable.)

Meta: "BUG" may be a stretch here - I don't doubt that the behaviour described is intentional, but it's still surprising, and as far as I can tell undocumented (I couldn't find any hints to this behaviour at https://numpy.org/doc/stable/reference/arrays.datetime.html). In which case this is at best a doc bug.

Reproduce the code example:

import numpy as np
x, y, z = np.timedelta64(1, "ms"), np.timedelta64(2), np.timedelta64(5, "ns")
print("x < y < z:", x < y < z)
print("x < z:", x < z)

Error message:

Python and NumPy Versions:

NumPy 2.2.2
Python 3.13.1 (main, Dec 7 2024, 10:29:14) [Clang 16.0.0 (clang-1600.0.26.4)]

Runtime Environment:

No response

Context for the issue:

This doesn't affect my work - we've already worked around this issue in our own code. (I think the lesson learned is "to avoid surprises, always provide a unit when using np.timedelta64".)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions