You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
BUG: astype(object) downcasts for datetime-dtype #12550
The dtype np.object_ is the most general catch-all type to contain arbitrary python objects. As such, .astype(object) should preferably not upcast, but certainly never downcast:
This is also inconsistent because passing an np.datetime64 to a constructor with dtype=object does not change it to datetime.datetime, so I was really surprised that .astype(object) does something different.
Well, the current state does seem strange. But I am not sure I like to change the behaviour because of something that on first sight seems rather hypothetical? (I mean changing the behaviour to returning datetime64, which seems pretty different.)
Do you actually work with dates past 10000 years? If that is a real use case, maybe we should see that python allows it rather?
Well, the current state does seem strange. But I am not sure I like to change the behaviour because of something that on first sight seems rather hypothetical? (I mean changing the behaviour to returning datetime64, which seems pretty different.)
I don't really get that point. The underlying values were datetime64 to begin with, why should astype(object) change the values (rather than just the dtype of the array)?
I understand of course that other astype-cases deliberately change the values (indeed, that's often the whole point of the method call), but object is special as the most general container, and should never need to cast at all.
Do you actually work with dates past 10000 years? If that is a real use case, maybe we should see that python allows it rather?
This is not an issue of date range limitations (to me). I'm writing lots of parametrized tests for a larger pandas-PR, and this discrepancy between dtype=object in the constructor and .astype(object) caught me out.
This is annoying, but... If you look closer, you will notice that also other types cast to the python version. For datetime this is a bigger step/change and also annoying.
What I mean is that we use .item()'s "convert to a python object" logic for datetime:
This assumes that numpy datetimes can be safely cast to python datetimes (which is not quite true)
But: Changing this is a pretty large change that needs to be thoroughly discussed (at least as far as I can see). For example, what will happen with matplotlib, and all the other users down there that (unwittingly) are using it to get datetime objects.
So, yes, this is not a safe cast. And yes it is utterly broken. But, I need a a lot more to be convinced that changing the cast from returning datetime objects to returning numpy datetime64 objects will not have a huge impact on downstream.
If such a fix would actually fix bugs for downstream in the long run, it would be more compelling. But it seems to me that for most users the bug will be very mild...
@seberg
We got side-tracked a bit with the datetime vs datetime64 - I see your points, even though I believe downstream effort is not a good reason to keep something in an "utterly broken" state. That's why there's version numbers. ;-)
I can work around the datetime/datetime64 thing, but the ints that get returned in the OP are really a killer.
I noticed that years ago I once glanced at changing the default behaviour for all types here (so that the object cast would retain the numpy type). But I am not quite sure we should do it.
EDIT: or well, aim for it maybe. First, there is no way to warn about it. Second, we probably have no clue about how disruptive that would be.
1. Only datetime64
2. Only rounded / truncated datetime
3. A mixture of datetime and int
4. A mixture of datetime64 and datetime
Right now, we do 3.
How about adding a keyword argument to .astype and related methods, such that the user can choose between those four options? I usually want a truncated datetime, but maybe sometimes a datetime64. I never want int.
I don't know if anyone has the cycles/enthusiasm to dive into this one again. But I fixed some infinite recursions here recently which may make this more feasible.
(Of course it is still a breaking change for things that know how to do deal with Python datetimes but not NumPy ones and currently can work via datetime_arr + other_obj.)
Activity
eric-wieser commentedon Dec 14, 2018
Note that the result is usually a
datetime.timedelta, if one is possible to create:h-vetinari commentedon Dec 14, 2018
Fair enough, as long as it's not an int... ;-)
eric-wieser commentedon Dec 14, 2018
Well in this case, it doesn't fit in a date time, so we don't have that option.
Is it better to return:
Right now, we do 3.
h-vetinari commentedon Dec 15, 2018
To me the answer is clearly 1 (should be clear that a mixture is bound to inconsistencies...).
TBH, I was really surprised that (from your example):
rather than
This is also inconsistent because passing an
np.datetime64to a constructor withdtype=objectdoes not change it todatetime.datetime, so I was really surprised that.astype(object)does something different.seberg commentedon Dec 15, 2018
Well, the current state does seem strange. But I am not sure I like to change the behaviour because of something that on first sight seems rather hypothetical? (I mean changing the behaviour to returning datetime64, which seems pretty different.)
Do you actually work with dates past 10000 years? If that is a real use case, maybe we should see that python allows it rather?
h-vetinari commentedon Dec 17, 2018
@seberg
I don't really get that point. The underlying values were
datetime64to begin with, why shouldastype(object)change the values (rather than just the dtype of the array)?I understand of course that other
astype-cases deliberately change the values (indeed, that's often the whole point of the method call), butobjectis special as the most general container, and should never need to cast at all.This is not an issue of date range limitations (to me). I'm writing lots of parametrized tests for a larger pandas-PR, and this discrepancy between
dtype=objectin the constructor and.astype(object)caught me out.seberg commentedon Dec 17, 2018
This is annoying, but... If you look closer, you will notice that also other types cast to the python version. For datetime this is a bigger step/change and also annoying.
What I mean is that we use
.item()'s "convert to a python object" logic for datetime:So, yes, this is not a safe cast. And yes it is utterly broken. But, I need a a lot more to be convinced that changing the cast from returning
datetimeobjects to returning numpydatetime64objects will not have a huge impact on downstream.If such a fix would actually fix bugs for downstream in the long run, it would be more compelling. But it seems to me that for most users the bug will be very mild...
seberg commentedon Dec 17, 2018
Note that this discrepancy occurs also for all of the numerical types in numpy, even if it may be just as surprising there.
h-vetinari commentedon Dec 18, 2018
@seberg
We got side-tracked a bit with the
datetimevsdatetime64- I see your points, even though I believe downstream effort is not a good reason to keep something in an "utterly broken" state. That's why there's version numbers. ;-)I can work around the
datetime/datetime64thing, but theintsthat get returned in the OP are really a killer.seberg commentedon Dec 30, 2018
I noticed that years ago I once glanced at changing the default behaviour for all types here (so that the object cast would retain the numpy type). But I am not quite sure we should do it.
EDIT: or well, aim for it maybe. First, there is no way to warn about it. Second, we probably have no clue about how disruptive that would be.
eric-wieser commentedon Dec 30, 2018
seberg commentedon Jan 3, 2019
There seem to be some similar odd casts noted in gh-5180, will close that one in favor if this one.
eric-wieser commentedon Feb 18, 2019
This is a duplicate of #8546 (closed) and #7619
gerritholl commentedon Feb 18, 2019
How about adding a keyword argument to
.astypeand related methods, such that the user can choose between those four options? I usually want a truncated datetime, but maybe sometimes a datetime64. I never want int.50 remaining items
seberg commentedon Aug 7, 2024
I don't know if anyone has the cycles/enthusiasm to dive into this one again. But I fixed some infinite recursions here recently which may make this more feasible.
(Of course it is still a breaking change for things that know how to do deal with Python datetimes but not NumPy ones and currently can work via
datetime_arr + other_obj.)BUG: return numpy scalars instead of ints from datetime64/timedelta64…
BUG: return numpy scalars instead of ints from datetime64/timedelta64…
BUG: return numpy scalars instead of ints from datetime64/timedelta64…
BUG: return numpy scalars instead of ints from datetime64/timedelta64…
BUG: return numpy scalars instead of ints from datetime64/timedelta64…
BUG: return numpy scalars instead of ints from datetime64/timedelta64…
BUG: return numpy scalars instead of ints from datetime64/timedelta64…
BUG: return numpy scalars instead of ints from datetime64/timedelta64…
BUG: return numpy scalars instead of ints from datetime64/timedelta64…