Skip to content

ENH: (GH4629) Support for using a DatetimeIndex/PeriodsIndex directly in a datelike calculation #4641

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 1 commit into from
Aug 24, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/source/release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pandas 0.13
is frequency conversion.
- Performance improvements with ``__getitem__`` on ``DataFrames`` with
when the key is a column
- Support for using a ``DatetimeIndex/PeriodsIndex`` directly in a datelike calculation
e.g. s-s.index (:issue:`4629`)

**API Changes**

Expand Down
12 changes: 8 additions & 4 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,16 @@ def wrapper(self, other, name=name):
coerce = 'compat' if _np_version_under1p7 else True

# convert the argument to an ndarray
def convert_to_array(values):
def convert_to_array(values, other=None):
if not is_list_like(values):
values = np.array([values])
inferred_type = lib.infer_dtype(values)
if inferred_type in set(['datetime64','datetime','date','time']):
# a datetlike
if not (isinstance(values, (pa.Array, Series)) and com.is_datetime64_dtype(values)):
values = tslib.array_to_datetime(values)
elif isinstance(values, DatetimeIndex):
other = values = values.to_series()
elif inferred_type in set(['timedelta']):
# have a timedelta, convert to to ns here
values = com._possibly_cast_to_timedelta(values, coerce=coerce)
Expand All @@ -121,6 +123,8 @@ def convert_to_array(values):
# py3 compat where dtype is 'm' but is an integer
if values.dtype.kind == 'm':
values = values.astype('timedelta64[ns]')
elif isinstance(values, PeriodIndex):
other = values = values.to_timestamp().to_series()
elif name not in ['__truediv__','__div__','__mul__']:
raise TypeError("incompatible type for a datetime/timedelta operation [{0}]".format(name))
elif isinstance(values[0],DateOffset):
Expand All @@ -134,11 +138,11 @@ def convert_to_array(values):
else:
raise TypeError("incompatible type [{0}] for a datetime/timedelta operation".format(pa.array(values).dtype))

return values
return values, other

# convert lhs and rhs
lvalues = convert_to_array(lvalues)
rvalues = convert_to_array(rvalues)
lvalues,_ = convert_to_array(lvalues)
rvalues,other = convert_to_array(rvalues,other)
Copy link
Contributor

Choose a reason for hiding this comment

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

am I reading this wrong, or are you converting other to None unless it's a PeriodIndex or DatetimeIndex?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nope...it comes in an out as the same (unless the date/period indexdex convert it)...I needed to do this because its needed below...a bit hacky, but didn't see a better way around it


is_datetime_rhs = com.is_datetime64_dtype(rvalues)
is_timedelta_rhs = com.is_timedelta64_dtype(rvalues) or (not is_datetime_rhs and _np_version_under1p7)
Expand Down
24 changes: 24 additions & 0 deletions pandas/tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -2319,6 +2319,30 @@ def test_sub_of_datetime_from_TimeSeries(self):
result = com._possibly_cast_to_timedelta(np.abs(a - b))
self.assert_(result.dtype == 'timedelta64[ns]')

def test_datetime64_with_index(self):

# arithmetic integer ops with an index
s = Series(np.random.randn(5))
expected = s-s.index.to_series()
result = s-s.index
assert_series_equal(result,expected)

# GH 4629
# arithmetic datetime64 ops with an index
s = Series(date_range('20130101',periods=5),index=date_range('20130101',periods=5))
expected = s-s.index.to_series()
result = s-s.index
assert_series_equal(result,expected)

result = s-s.index.to_period()
assert_series_equal(result,expected)

df = DataFrame(np.random.randn(5,2),index=date_range('20130101',periods=5))
df['date'] = Timestamp('20130102')
df['expected'] = df['date']-df.index.to_series()
df['result'] = df['date']-df.index
assert_series_equal(df['result'],df['expected'])

def test_timedelta64_nan(self):

from pandas import tslib
Expand Down