Skip to content

Commit 2030a07

Browse files
jbrockmendeljreback
authored andcommitted
datetimelike indexes add/sub zero-dim integer arrays (#19013)
1 parent ace4663 commit 2030a07

File tree

6 files changed

+48
-27
lines changed

6 files changed

+48
-27
lines changed

doc/source/whatsnew/v0.23.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ Numeric
368368
^^^^^^^
369369

370370
- Bug in :func:`Series.__sub__` subtracting a non-nanosecond ``np.datetime64`` object from a ``Series`` gave incorrect results (:issue:`7996`)
371-
-
371+
- Bug in :class:`DatetimeIndex`, :class:`TimedeltaIndex` addition and subtraction of zero-dimensional integer arrays gave incorrect results (:issue:`19012`)
372372
-
373373

374374
Categorical

pandas/core/indexes/datetimelike.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,8 @@ def __add__(self, other):
669669
from pandas.core.index import Index
670670
from pandas.core.indexes.timedeltas import TimedeltaIndex
671671
from pandas.tseries.offsets import DateOffset
672+
673+
other = lib.item_from_zerodim(other)
672674
if is_timedelta64_dtype(other):
673675
return self._add_delta(other)
674676
elif isinstance(self, TimedeltaIndex) and isinstance(other, Index):
@@ -689,6 +691,7 @@ def __add__(self, other):
689691
return self._add_datelike(other)
690692
else: # pragma: no cover
691693
return NotImplemented
694+
692695
cls.__add__ = __add__
693696
cls.__radd__ = __add__
694697

@@ -697,6 +700,8 @@ def __sub__(self, other):
697700
from pandas.core.indexes.datetimes import DatetimeIndex
698701
from pandas.core.indexes.timedeltas import TimedeltaIndex
699702
from pandas.tseries.offsets import DateOffset
703+
704+
other = lib.item_from_zerodim(other)
700705
if is_timedelta64_dtype(other):
701706
return self._add_delta(-other)
702707
elif isinstance(self, TimedeltaIndex) and isinstance(other, Index):
@@ -724,6 +729,7 @@ def __sub__(self, other):
724729

725730
else: # pragma: no cover
726731
return NotImplemented
732+
727733
cls.__sub__ = __sub__
728734

729735
def __rsub__(self, other):
@@ -737,8 +743,10 @@ def _add_delta(self, other):
737743
return NotImplemented
738744

739745
def _add_delta_td(self, other):
740-
# add a delta of a timedeltalike
741-
# return the i8 result view
746+
"""
747+
Add a delta of a timedeltalike
748+
return the i8 result view
749+
"""
742750

743751
inc = delta_to_nanoseconds(other)
744752
new_values = checked_add_with_arr(self.asi8, inc,
@@ -748,8 +756,10 @@ def _add_delta_td(self, other):
748756
return new_values.view('i8')
749757

750758
def _add_delta_tdi(self, other):
751-
# add a delta of a TimedeltaIndex
752-
# return the i8 result view
759+
"""
760+
Add a delta of a TimedeltaIndex
761+
return the i8 result view
762+
"""
753763

754764
# delta operation
755765
if not len(self) == len(other):

pandas/tests/indexes/conftest.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pytest
2+
import numpy as np
23

34
import pandas.util.testing as tm
45
from pandas.core.indexes.api import Index, MultiIndex
@@ -22,3 +23,9 @@
2223
ids=lambda x: type(x).__name__)
2324
def indices(request):
2425
return request.param
26+
27+
28+
@pytest.fixture(params=[1, np.array(1, dtype=np.int64)])
29+
def one(request):
30+
# zero-dim integer array behaves like an integer
31+
return request.param

pandas/tests/indexes/datetimes/test_arithmetic.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -58,36 +58,37 @@ def test_dti_radd_timestamp_raises(self):
5858
# -------------------------------------------------------------
5959
# Binary operations DatetimeIndex and int
6060

61-
def test_dti_add_int(self, tz):
61+
def test_dti_add_int(self, tz, one):
62+
# Variants of `one` for #19012
6263
rng = pd.date_range('2000-01-01 09:00', freq='H',
6364
periods=10, tz=tz)
64-
result = rng + 1
65+
result = rng + one
6566
expected = pd.date_range('2000-01-01 10:00', freq='H',
6667
periods=10, tz=tz)
6768
tm.assert_index_equal(result, expected)
6869

69-
def test_dti_iadd_int(self, tz):
70+
def test_dti_iadd_int(self, tz, one):
7071
rng = pd.date_range('2000-01-01 09:00', freq='H',
7172
periods=10, tz=tz)
7273
expected = pd.date_range('2000-01-01 10:00', freq='H',
7374
periods=10, tz=tz)
74-
rng += 1
75+
rng += one
7576
tm.assert_index_equal(rng, expected)
7677

77-
def test_dti_sub_int(self, tz):
78+
def test_dti_sub_int(self, tz, one):
7879
rng = pd.date_range('2000-01-01 09:00', freq='H',
7980
periods=10, tz=tz)
80-
result = rng - 1
81+
result = rng - one
8182
expected = pd.date_range('2000-01-01 08:00', freq='H',
8283
periods=10, tz=tz)
8384
tm.assert_index_equal(result, expected)
8485

85-
def test_dti_isub_int(self, tz):
86+
def test_dti_isub_int(self, tz, one):
8687
rng = pd.date_range('2000-01-01 09:00', freq='H',
8788
periods=10, tz=tz)
8889
expected = pd.date_range('2000-01-01 08:00', freq='H',
8990
periods=10, tz=tz)
90-
rng -= 1
91+
rng -= one
9192
tm.assert_index_equal(rng, expected)
9293

9394
# -------------------------------------------------------------

pandas/tests/indexes/period/test_arithmetic.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -131,19 +131,21 @@ def test_add_iadd(self):
131131
period.IncompatibleFrequency, msg):
132132
rng += delta
133133

134-
# int
134+
def test_pi_add_int(self, one):
135+
# Variants of `one` for #19012
135136
rng = pd.period_range('2000-01-01 09:00', freq='H', periods=10)
136-
result = rng + 1
137+
result = rng + one
137138
expected = pd.period_range('2000-01-01 10:00', freq='H', periods=10)
138139
tm.assert_index_equal(result, expected)
139-
rng += 1
140+
rng += one
140141
tm.assert_index_equal(rng, expected)
141142

142-
def test_sub(self):
143+
@pytest.mark.parametrize('five', [5, np.array(5, dtype=np.int64)])
144+
def test_sub(self, five):
143145
rng = period_range('2007-01', periods=50)
144146

145-
result = rng - 5
146-
exp = rng + (-5)
147+
result = rng - five
148+
exp = rng + (-five)
147149
tm.assert_index_equal(result, exp)
148150

149151
def test_sub_isub(self):

pandas/tests/indexes/timedeltas/test_arithmetic.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -121,28 +121,29 @@ def test_ufunc_coercions(self):
121121
# -------------------------------------------------------------
122122
# Binary operations TimedeltaIndex and integer
123123

124-
def test_tdi_add_int(self):
124+
def test_tdi_add_int(self, one):
125+
# Variants of `one` for #19012
125126
rng = timedelta_range('1 days 09:00:00', freq='H', periods=10)
126-
result = rng + 1
127+
result = rng + one
127128
expected = timedelta_range('1 days 10:00:00', freq='H', periods=10)
128129
tm.assert_index_equal(result, expected)
129130

130-
def test_tdi_iadd_int(self):
131+
def test_tdi_iadd_int(self, one):
131132
rng = timedelta_range('1 days 09:00:00', freq='H', periods=10)
132133
expected = timedelta_range('1 days 10:00:00', freq='H', periods=10)
133-
rng += 1
134+
rng += one
134135
tm.assert_index_equal(rng, expected)
135136

136-
def test_tdi_sub_int(self):
137+
def test_tdi_sub_int(self, one):
137138
rng = timedelta_range('1 days 09:00:00', freq='H', periods=10)
138-
result = rng - 1
139+
result = rng - one
139140
expected = timedelta_range('1 days 08:00:00', freq='H', periods=10)
140141
tm.assert_index_equal(result, expected)
141142

142-
def test_tdi_isub_int(self):
143+
def test_tdi_isub_int(self, one):
143144
rng = timedelta_range('1 days 09:00:00', freq='H', periods=10)
144145
expected = timedelta_range('1 days 08:00:00', freq='H', periods=10)
145-
rng -= 1
146+
rng -= one
146147
tm.assert_index_equal(rng, expected)
147148

148149
# -------------------------------------------------------------

0 commit comments

Comments
 (0)