Skip to content

BUG: Ensure sign(timedelta64('nat')) returns timedelta64('nat') #29498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

WarrenWeckesser
Copy link
Member

@WarrenWeckesser WarrenWeckesser commented Aug 1, 2025

Closes gh-29496.

@jorenham jorenham changed the title BUG: Ensure sign(datetime64('nat')) returns datetime64('nat') BUG: Ensure sign(timedelta64('nat')) returns timedelta64('nat') Aug 1, 2025
@WarrenWeckesser
Copy link
Member Author

Oops... thanks @jorenham. If this gets merged, the commit message should also be fixed to say 'timedelta64' instead of 'datetime64'. I can force-push an updated commit, but I'll hold off until someone has a chance to review.

@jorenham
Copy link
Member

jorenham commented Aug 1, 2025

Oops... thanks @jorenham. If this gets merged, the commit message should also be fixed to say 'timedelta64' instead of 'datetime64'. I can force-push an updated commit, but I'll hold off until someone has a chance to review.

squash merging is also an option

nat = np.timedelta64('nat', *args)
sgn = np.sign(nat)
assert sgn.dtype == nat.dtype
assert np.isnat(sgn)
Copy link
Contributor

Choose a reason for hiding this comment

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

I confirmed that the test fails locally when reverting the source patch.

I also checked that on this branch, with multiple array entries, the behavior still looks sensible (I think):

nat = np.timedelta64('nat', *args)
arr = np.array([np.timedelta64(-1, 'h'), nat, nat, np.timedelta64(1, 'h')])
sgn = np.sign(arr)
print(sgn)
# [   -1 'NaT' 'NaT'     1] 

This seems almost straightforward enough for me to merge directly, but I'm probably sufficiently inactive that I should let another dev take a quick look.

@@ -581,6 +581,15 @@ def test_timedelta_scalar_construction_units(self):
assert_equal(np.datetime64('now').dtype,
np.dtype('M8[s]'))

@pytest.mark.parametrize('args', [(), ('s',)])
Copy link
Member

@jorenham jorenham Aug 5, 2025

Choose a reason for hiding this comment

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

In case of non-NaT values, with 'ns' and 'M' you get _.item() -> int, but with 's' you het _.item() -> datetime.timedelta. If that's irrelevant for the C changes here, then feel free to ignore me, but otherwise something like this could help test it:

Suggested change
@pytest.mark.parametrize('args', [(), ('s',)])
@pytest.mark.parametrize('args', [(), ('ns', 's', 'M')])

Copy link
Member Author

Choose a reason for hiding this comment

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

@jorenham, that is issue #28596. It should be irrelevant here.

@seberg
Copy link
Member

seberg commented Aug 5, 2025

I am confused, did you actually land on the sign of timedelta should be a timedelta at all?

@WarrenWeckesser
Copy link
Member Author

@seberg wrote

I am confused, did you actually land on the sign of timedelta should be a timedelta at all?

Returning timedelta64 is already the current behavior. This PR only changes the specific value returned when the input to sign is a NAT timedelta64. Instead of sign(timedelta64('nat', 's')) returning timedelta64(-1, 's'), we get timedelta64('NaT', 's'). This makes the behavior consistent with the handling of floats, where sign(nan) returns nan.

Changing the return type for timedelta64 inputs would have to be part of a bigger discussion of the sign API, such as the ones in the sign(-0.0) issue and #8463.

@seberg
Copy link
Member

seberg commented Aug 5, 2025

I suppose it's not clear to me that there is a point in fixing this if we want to change the return type. Unless we have a rough agreement to make the return type float, so that we can preserve NaT there by going to NaN.

But OK, if you think this is best, since it clearly returns nonsense right now, fine. I was just slightly worried that transitioning away from it might just get harder with this.

@WarrenWeckesser
Copy link
Member Author

Yeah, I get your point. I'll mark this as draft for now, and return to it (if necessary) when the bigger issue of the sign API is resolved.

@WarrenWeckesser WarrenWeckesser marked this pull request as draft August 5, 2025 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BUG: sign(timedelta64('nat')) returns -1; expected timedelta64('nat')
4 participants