Skip to content

ENH: timedelta64 and datetime64 inherit from np.timebase#10701

Closed
shoyer wants to merge 6 commits intonumpy:mainfrom
shoyer:timedelta-not-integer
Closed

ENH: timedelta64 and datetime64 inherit from np.timebase#10701
shoyer wants to merge 6 commits intonumpy:mainfrom
shoyer:timedelta-not-integer

Conversation

@shoyer
Copy link
Copy Markdown
Member

@shoyer shoyer commented Mar 7, 2018

This is attempt to fix #10685 by making both np.timedelta64 and np.datetime64 inherit from a common base class, which I have tentatively called np.timeunit (which is turn inherits from np.generic).

Note that this currently doesn't work. PyTimeunitArrType_Type ends up defined after the PyDatetimeArrType_Type and PyTimedeltaArrType_Type types for which it's supposed to be the base class in the autogenerated __multiarray_api.c and __multiarray_api.h, so the compiler fails with errors about undeclared identifiers. I think this may be because I added it to the end of NumPy C API.

If anyone has suggestions for how to make this work, I'd love to hear them. This is my first time attempting to muck with NumPy's C API.

@mhvk
Copy link
Copy Markdown
Contributor

mhvk commented Mar 7, 2018

What is this PyTimeIntegerArrType_Type - https://github.com/numpy/numpy/pull/10701/files#diff-6a57805e2d73eee0dae975f83e2bf678R70 - it looks like it is put there to be the base class for both datetime64 and timedelta. A quick find/grep shows it is not used anywhere... Might it be an idea to use it? (Would probably solve your ordering issue...)

@shoyer
Copy link
Copy Markdown
Member Author

shoyer commented Mar 7, 2018

Apparently something about my local dev environment is stale -- this actually builds successfully in CI!

@mhvk I was wondering the same thing. It does look like TimeInteger originally served this purpose, but the same is a poor choice -- it seems wrong to call either datetime64 or timedelta64 integer of any kind.

See also @mwiebe commit where he removed TimeInteger in favor of making timedelta inherit from integer: de71993

Any thoughts on the name np.timeunit? np.timequantity is potentially more accurate (per the quantity vs unit distinction in unit libraries), but the name is a bit long. Maybe that's OK for rarely used baseclass, though.

@mhvk
Copy link
Copy Markdown
Contributor

mhvk commented Mar 7, 2018

Good that there are no build problems!

On TimeInteger, I somewhat disagree with the commit text you linked to: datetime64 does have a zero point (unix time zero), and it represents an integer offset from that - be it with an associated unit. It is different, though, in that adding two datetime64 doesn't really make any sense, and hence I agree with the commit itself in distinguishing between offsets and "absolute" times (we do the same for astropy: Time and TimeDelta). It also makes some sense to not inherit from integer, since without the unit, one really doesn't know what the number means (but then again, the number is an integer -- just one with special properties...).

About the name, I'd be somewhat keen to reserve quantity for floats, so how about just np.timebase or np.generictime? Alternatively, is there much advantage to having a base class? Could we just let both inherit from np.generic?

@shoyer
Copy link
Copy Markdown
Member Author

shoyer commented Mar 7, 2018

I like np.timebase. I think the shared base class is marginally useful, since timedelta64 and datetime64 have some similar designs/uses. For example, it tells you if np.isnat() is well defined.

@njsmith
Copy link
Copy Markdown
Member

njsmith commented Mar 8, 2018

What's the advantage of having a common base class at all? They're fundamentally different, incommensurable types. Maybe they should both just be directly under np.generic?

@shoyer
Copy link
Copy Markdown
Member Author

shoyer commented Mar 8, 2018

What's the advantage of having a common base class at all? They're fundamentally different, incommensurable types. Maybe they should both just be directly under np.generic?

I'm not strongly opposed to this.

The main advantage is easy categorization, e.g.,

def isna(array):
    if issubclass(array.dtype.type, np.floating):
        return np.isnan(array)
    elif issubclass(array.dtype.type, np.timebase):
        return np.isnat(array)
    else:
        return np.zeros_like(array, dtype=bool)

But I agree that with only two types it's pretty marginal.

NumPy does this sort of thing itself in a few places, e.g., in numpy/core/arrayprint.py.

@mhvk
Copy link
Copy Markdown
Contributor

mhvk commented Mar 8, 2018

Also not sure how useful it is, though the two do share the unit mechanism; if this were a python class, it would live in a common base class. Anyway, I guess there are three options of what they should inherit from:

  1. a new PyTimebaseArrType_Type;
  2. the old PyTimeIntegerArrType_Type;
  3. nothing in common, so PyGenericArrType_Type.

Here, for option (2), I don't think we need to inherit also from Integer -- TimeInteger currently does not inherit from anything.

I'm mildly in favour of inheriting from a common class, and very mildly prefer option (2), as it uses what now is an empty, confusing slot in the C api. (Indeed, is there any inconvenience associated with changing the numpy C api? If so, would it be a fourth option to rename PyIntegerArrType_Type?)

But most important would seem to be to break the direct inheritance of TimeDelta on SignedInteger.

@shoyer shoyer changed the title WIP: timedelta64 and datetime64 inherit from np.timeunit ENH: timedelta64 and datetime64 inherit from np.timebase Mar 8, 2018
@charris
Copy link
Copy Markdown
Member

charris commented Apr 6, 2018

Enhancements should have a release note.

Base automatically changed from master to main March 4, 2021 02:04
@InessaPawson InessaPawson added the 52 - Inactive Pending author response label Jun 8, 2022
@HaoZeke HaoZeke added the 56 - Needs Release Note. Needs an entry in doc/release/upcoming_changes label Jun 8, 2022
@mattip
Copy link
Copy Markdown
Member

mattip commented Jul 3, 2024

Closing, I think the experiment was useful but the two classes do not share enough to have a common ancestor.

@mattip mattip closed this Jul 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

np.timedelta64 should not be an subclass of np.integer

7 participants