Skip to content

Commit

Permalink
Use ._tshift internally for datetimelike ops
Browse files Browse the repository at this point in the history
In preperation for PeriodArray / DatetimeArray / TimedeltaArray.

Index.shift has a different meaning from ExtensionArray.shift.

- Index.shift pointwise shifts each element by some amount
- ExtensionArray.shift shits the *position* of each value in the array
  padding the end with NA

This is going to get confusing. This PR tries to avoid some of that by
internally using a new `_tshift` method (time-shift) when we want to do pointwise
shifting of each value. Places that know they want that behavior (like in the
datetimelike ops) should use that.
  • Loading branch information
TomAugspurger committed Oct 2, 2018
1 parent 1d9f76c commit 23e5cfc
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 6 deletions.
23 changes: 20 additions & 3 deletions pandas/core/arrays/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ def _sub_period_array(self, other):
def _addsub_int_array(self, other, op):
"""
Add or subtract array-like of integers equivalent to applying
`shift` pointwise.
`_tshift` pointwise.
Parameters
----------
Expand Down Expand Up @@ -553,6 +553,23 @@ def shift(self, periods, freq=None):
--------
Index.shift : Shift values of Index.
"""
return self._tshift(periods=periods, freq=freq)

def _tshift(self, periods, freq=None):
"""
Shift each value by `periods`.
Note this is different from ExtensionArray.shift, which
shifts the *position* of each element, padding the end with
missing values.
Parameters
----------
periods : int
Number of periods to shift by.
freq : pandas.DateOffset, pandas.Timedelta, or string
Frequency increment to shift by.
"""
if freq is not None and freq != self.freq:
if isinstance(freq, compat.string_types):
freq = frequencies.to_offset(freq)
Expand Down Expand Up @@ -600,7 +617,7 @@ def __add__(self, other):
elif lib.is_integer(other):
# This check must come after the check for np.timedelta64
# as is_integer returns True for these
result = self.shift(other)
result = self._tshift(other)

# array-like others
elif is_timedelta64_dtype(other):
Expand Down Expand Up @@ -652,7 +669,7 @@ def __sub__(self, other):
elif lib.is_integer(other):
# This check must come after the check for np.timedelta64
# as is_integer returns True for these
result = self.shift(-other)
result = self._tshift(-other)
elif isinstance(other, Period):
result = self._sub_period(other)

Expand Down
9 changes: 6 additions & 3 deletions pandas/core/arrays/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ def _add_offset(self, other):
if base != self.freq.rule_code:
msg = DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr)
raise IncompatibleFrequency(msg)
return self.shift(other.n)
return self._tshift(other.n)

def _add_delta_td(self, other):
assert isinstance(other, (timedelta, np.timedelta64, Tick))
Expand All @@ -307,7 +307,7 @@ def _add_delta_td(self, other):
if isinstance(own_offset, Tick):
offset_nanos = delta_to_nanoseconds(own_offset)
if np.all(nanos % offset_nanos == 0):
return self.shift(nanos // offset_nanos)
return self._tshift(nanos // offset_nanos)

# raise when input doesn't have freq
raise IncompatibleFrequency("Input has different freq from "
Expand All @@ -317,7 +317,7 @@ def _add_delta_td(self, other):

def _add_delta(self, other):
ordinal_delta = self._maybe_convert_timedelta(other)
return self.shift(ordinal_delta)
return self._tshift(ordinal_delta)

def shift(self, n):
"""
Expand All @@ -332,6 +332,9 @@ def shift(self, n):
-------
shifted : Period Array/Index
"""
return self._tshift(n)

def _tshift(self, n):
values = self._ndarray_values + n * self.freq.n
if self.hasnans:
values[self._isnan] = iNaT
Expand Down

0 comments on commit 23e5cfc

Please sign in to comment.