Skip to content

implement TimedeltaArray asm8, to_timedelta64 #23205

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

Merged
merged 8 commits into from
Oct 23, 2018
16 changes: 16 additions & 0 deletions pandas/core/arrays/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,22 @@ def tz_localize(self, tz, ambiguous='raise', errors='raise'):
# ----------------------------------------------------------------
# Conversion Methods - Vectorized analogues of Timestamp methods

def to_datetime64(self):
"""
Return numpy datetime64[ns] representation of self. For timezone-aware
cases, the returned array represents UTC timestamps.

Returns
-------
ndarray[datetime64[ns]]
"""
return self.asi8.view('M8[ns]')

@property
def asm8(self):
"""Vectorized analogue of Timestamp.asm8"""
return self.to_datetime64()

def to_pydatetime(self):
"""
Return Datetime Array/Index as object ndarray of datetime.datetime
Expand Down
25 changes: 25 additions & 0 deletions pandas/core/arrays/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,31 @@ def to_pytimedelta(self):
"""
return tslibs.ints_to_pytimedelta(self.asi8)

def to_timedelta64(self):
"""
Return numpy array with timedelta64[ns] dtype

Returns
-------
ndarray[timedelta64[ns]]

Notes
-----
This returns a view on self, not a copy.

See also
--------
Timedelta.to_timedelta64
"""
return self.asi8.view('m8[ns]')
Copy link
Member

Choose a reason for hiding this comment

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

you are going a little bit in circles here, as asi8 itself is already self.values.view('i8') ?

Copy link
Member Author

Choose a reason for hiding this comment

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

I find asi8 much more explicit than alues (BTW as I mentioned to jreback the "v" key on my keyboard is sticky; I'm going to stop copy-pasting and let you guys infer the missing letter for a while).


@property
def asm8(self):
Copy link
Member

Choose a reason for hiding this comment

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

do we need both to_timedelta64 and asm8 ?

Copy link
Member Author

Choose a reason for hiding this comment

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

If we were starting fresh I would say no, but as it is I think consistency with the scalar type is really worthwhile. (and to your point aboe DatetimeIndex should have a to_datetime64 method)

"""
Vectorized analogue of Timedelta.asm8
"""
return self.to_timedelta64()

days = _field_accessor("days", "days",
" Number of days for each element. ")
seconds = _field_accessor("seconds", "seconds",
Expand Down
48 changes: 48 additions & 0 deletions pandas/tests/arrays/test_datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,30 @@ def test_to_period(self, datetime_index, freqstr):
# an EA-specific tm.assert_ function
tm.assert_index_equal(pd.Index(result), pd.Index(expected))

def test_asm8(self, datetime_index):
dti = datetime_index
arr = DatetimeArrayMixin(dti)

expected = np.array([x.asm8 for x in dti], dtype='M8[ns]')

result = dti.asm8
tm.assert_numpy_array_equal(result, expected)

result = arr.asm8
tm.assert_numpy_array_equal(result, expected)

def test_to_datetime64(self, datetime_index):
dti = datetime_index
arr = DatetimeArrayMixin(dti)

expected = np.array([x.asm8 for x in dti], dtype='M8[ns]')

result = dti.to_datetime64()
tm.assert_numpy_array_equal(result, expected)

result = arr.to_datetime64()
tm.assert_numpy_array_equal(result, expected)

@pytest.mark.parametrize('propname', pd.DatetimeIndex._bool_ops)
def test_bool_properties(self, datetime_index, propname):
# in this case _bool_ops is just `is_leap_year`
Expand Down Expand Up @@ -148,6 +172,30 @@ def test_astype_object(self):
assert asobj.dtype == 'O'
assert list(asobj) == list(tdi)

def test_asm8(self):
tdi = pd.TimedeltaIndex(['1 Hour', '3 Hours'])
arr = TimedeltaArrayMixin(tdi)

expected = np.array([3600, 10800], dtype='m8[ns]') * 1e9

result = tdi.asm8
tm.assert_numpy_array_equal(result, expected)

result = arr.asm8
tm.assert_numpy_array_equal(result, expected)

def test_to_timedelta64(self):
tdi = pd.TimedeltaIndex(['1 Hour', '3 Hours'])
arr = TimedeltaArrayMixin(tdi)

expected = np.array([3600, 10800], dtype='m8[ns]') * 1e9

result = tdi.to_timedelta64()
tm.assert_numpy_array_equal(result, expected)

result = arr.to_timedelta64()
tm.assert_numpy_array_equal(result, expected)

def test_to_pytimedelta(self, timedelta_index):
tdi = timedelta_index
arr = TimedeltaArrayMixin(tdi)
Expand Down