Skip to content

Commit 38e29ab

Browse files
authored
BUG: DatetimeIndex.shift with non-nano (#56117)
* BUG: DatetimeIndex.shift with non-nano * BUG: DatetimeIndex.shift with non-nano
1 parent bb9ef02 commit 38e29ab

File tree

3 files changed

+39
-31
lines changed

3 files changed

+39
-31
lines changed

doc/source/whatsnew/v2.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ Datetimelike
447447
- Bug in :func:`testing.assert_extension_array_equal` that could use the wrong unit when comparing resolutions (:issue:`55730`)
448448
- Bug in :func:`to_datetime` and :class:`DatetimeIndex` when passing a list of mixed-string-and-numeric types incorrectly raising (:issue:`55780`)
449449
- Bug in :func:`to_datetime` and :class:`DatetimeIndex` when passing mixed-type objects with a mix of timezones or mix of timezone-awareness failing to raise ``ValueError`` (:issue:`55693`)
450+
- Bug in :meth:`DatetimeIndex.shift` with non-nanosecond resolution incorrectly returning with nanosecond resolution (:issue:`56117`)
450451
- Bug in :meth:`DatetimeIndex.union` returning object dtype for tz-aware indexes with the same timezone but different units (:issue:`55238`)
451452
- Bug in :meth:`Index.is_monotonic_increasing` and :meth:`Index.is_monotonic_decreasing` always caching :meth:`Index.is_unique` as ``True`` when first value in index is ``NaT`` (:issue:`55755`)
452453
- Bug in :meth:`Index.view` to a datetime64 dtype with non-supported resolution incorrectly raising (:issue:`55710`)

pandas/core/indexes/datetimelike.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ def shift(self, periods: int = 1, freq=None) -> Self:
518518
# appropriate timezone from `start` and `end`, so tz does not need
519519
# to be passed explicitly.
520520
result = self._data._generate_range(
521-
start=start, end=end, periods=None, freq=self.freq
521+
start=start, end=end, periods=None, freq=self.freq, unit=self.unit
522522
)
523523
return type(self)._simple_new(result, name=self.name)
524524

pandas/tests/indexes/datetimes/methods/test_shift.py

+37-30
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ class TestDatetimeIndexShift:
2020
# -------------------------------------------------------------
2121
# DatetimeIndex.shift is used in integer addition
2222

23-
def test_dti_shift_tzaware(self, tz_naive_fixture):
23+
def test_dti_shift_tzaware(self, tz_naive_fixture, unit):
2424
# GH#9903
2525
tz = tz_naive_fixture
26-
idx = DatetimeIndex([], name="xxx", tz=tz)
26+
idx = DatetimeIndex([], name="xxx", tz=tz).as_unit(unit)
2727
tm.assert_index_equal(idx.shift(0, freq="h"), idx)
2828
tm.assert_index_equal(idx.shift(3, freq="h"), idx)
2929

@@ -32,50 +32,53 @@ def test_dti_shift_tzaware(self, tz_naive_fixture):
3232
name="xxx",
3333
tz=tz,
3434
freq="h",
35-
)
35+
).as_unit(unit)
3636
tm.assert_index_equal(idx.shift(0, freq="h"), idx)
3737
exp = DatetimeIndex(
3838
["2011-01-01 13:00", "2011-01-01 14:00", "2011-01-01 15:00"],
3939
name="xxx",
4040
tz=tz,
4141
freq="h",
42-
)
42+
).as_unit(unit)
4343
tm.assert_index_equal(idx.shift(3, freq="h"), exp)
4444
exp = DatetimeIndex(
4545
["2011-01-01 07:00", "2011-01-01 08:00", "2011-01-01 09:00"],
4646
name="xxx",
4747
tz=tz,
4848
freq="h",
49-
)
49+
).as_unit(unit)
5050
tm.assert_index_equal(idx.shift(-3, freq="h"), exp)
5151

52-
def test_dti_shift_freqs(self):
52+
def test_dti_shift_freqs(self, unit):
5353
# test shift for DatetimeIndex and non DatetimeIndex
5454
# GH#8083
55-
drange = date_range("20130101", periods=5)
55+
drange = date_range("20130101", periods=5, unit=unit)
5656
result = drange.shift(1)
5757
expected = DatetimeIndex(
5858
["2013-01-02", "2013-01-03", "2013-01-04", "2013-01-05", "2013-01-06"],
59+
dtype=f"M8[{unit}]",
5960
freq="D",
6061
)
6162
tm.assert_index_equal(result, expected)
6263

6364
result = drange.shift(-1)
6465
expected = DatetimeIndex(
6566
["2012-12-31", "2013-01-01", "2013-01-02", "2013-01-03", "2013-01-04"],
67+
dtype=f"M8[{unit}]",
6668
freq="D",
6769
)
6870
tm.assert_index_equal(result, expected)
6971

7072
result = drange.shift(3, freq="2D")
7173
expected = DatetimeIndex(
7274
["2013-01-07", "2013-01-08", "2013-01-09", "2013-01-10", "2013-01-11"],
75+
dtype=f"M8[{unit}]",
7376
freq="D",
7477
)
7578
tm.assert_index_equal(result, expected)
7679

77-
def test_dti_shift_int(self):
78-
rng = date_range("1/1/2000", periods=20)
80+
def test_dti_shift_int(self, unit):
81+
rng = date_range("1/1/2000", periods=20, unit=unit)
7982

8083
result = rng + 5 * rng.freq
8184
expected = rng.shift(5)
@@ -85,25 +88,27 @@ def test_dti_shift_int(self):
8588
expected = rng.shift(-5)
8689
tm.assert_index_equal(result, expected)
8790

88-
def test_dti_shift_no_freq(self):
91+
def test_dti_shift_no_freq(self, unit):
8992
# GH#19147
90-
dti = DatetimeIndex(["2011-01-01 10:00", "2011-01-01"], freq=None)
93+
dti = DatetimeIndex(["2011-01-01 10:00", "2011-01-01"], freq=None).as_unit(unit)
9194
with pytest.raises(NullFrequencyError, match="Cannot shift with no freq"):
9295
dti.shift(2)
9396

9497
@pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"])
95-
def test_dti_shift_localized(self, tzstr):
96-
dr = date_range("2011/1/1", "2012/1/1", freq="W-FRI")
98+
def test_dti_shift_localized(self, tzstr, unit):
99+
dr = date_range("2011/1/1", "2012/1/1", freq="W-FRI", unit=unit)
97100
dr_tz = dr.tz_localize(tzstr)
98101

99102
result = dr_tz.shift(1, "10min")
100103
assert result.tz == dr_tz.tz
101104

102-
def test_dti_shift_across_dst(self):
105+
def test_dti_shift_across_dst(self, unit):
103106
# GH 8616
104-
idx = date_range("2013-11-03", tz="America/Chicago", periods=7, freq="h")
105-
s = Series(index=idx[:-1], dtype=object)
106-
result = s.shift(freq="h")
107+
idx = date_range(
108+
"2013-11-03", tz="America/Chicago", periods=7, freq="h", unit=unit
109+
)
110+
ser = Series(index=idx[:-1], dtype=object)
111+
result = ser.shift(freq="h")
107112
expected = Series(index=idx[1:], dtype=object)
108113
tm.assert_series_equal(result, expected)
109114

@@ -115,24 +120,26 @@ def test_dti_shift_across_dst(self):
115120
[1, "2014-11-14 01:00:00"],
116121
],
117122
)
118-
def test_dti_shift_near_midnight(self, shift, result_time):
123+
def test_dti_shift_near_midnight(self, shift, result_time, unit):
119124
# GH 8616
120125
dt = datetime(2014, 11, 14, 0)
121126
dt_est = pytz.timezone("EST").localize(dt)
122-
s = Series(data=[1], index=[dt_est])
123-
result = s.shift(shift, freq="h")
124-
expected = Series(1, index=DatetimeIndex([result_time], tz="EST"))
127+
idx = DatetimeIndex([dt_est]).as_unit(unit)
128+
ser = Series(data=[1], index=idx)
129+
result = ser.shift(shift, freq="h")
130+
exp_index = DatetimeIndex([result_time], tz="EST").as_unit(unit)
131+
expected = Series(1, index=exp_index)
125132
tm.assert_series_equal(result, expected)
126133

127-
def test_shift_periods(self):
134+
def test_shift_periods(self, unit):
128135
# GH#22458 : argument 'n' was deprecated in favor of 'periods'
129-
idx = date_range(start=START, end=END, periods=3)
136+
idx = date_range(start=START, end=END, periods=3, unit=unit)
130137
tm.assert_index_equal(idx.shift(periods=0), idx)
131138
tm.assert_index_equal(idx.shift(0), idx)
132139

133140
@pytest.mark.parametrize("freq", ["B", "C"])
134-
def test_shift_bday(self, freq):
135-
rng = date_range(START, END, freq=freq)
141+
def test_shift_bday(self, freq, unit):
142+
rng = date_range(START, END, freq=freq, unit=unit)
136143
shifted = rng.shift(5)
137144
assert shifted[0] == rng[5]
138145
assert shifted.freq == rng.freq
@@ -145,18 +152,18 @@ def test_shift_bday(self, freq):
145152
assert shifted[0] == rng[0]
146153
assert shifted.freq == rng.freq
147154

148-
def test_shift_bmonth(self):
149-
rng = date_range(START, END, freq=pd.offsets.BMonthEnd())
155+
def test_shift_bmonth(self, unit):
156+
rng = date_range(START, END, freq=pd.offsets.BMonthEnd(), unit=unit)
150157
shifted = rng.shift(1, freq=pd.offsets.BDay())
151158
assert shifted[0] == rng[0] + pd.offsets.BDay()
152159

153-
rng = date_range(START, END, freq=pd.offsets.BMonthEnd())
160+
rng = date_range(START, END, freq=pd.offsets.BMonthEnd(), unit=unit)
154161
with tm.assert_produces_warning(pd.errors.PerformanceWarning):
155162
shifted = rng.shift(1, freq=pd.offsets.CDay())
156163
assert shifted[0] == rng[0] + pd.offsets.CDay()
157164

158-
def test_shift_empty(self):
165+
def test_shift_empty(self, unit):
159166
# GH#14811
160-
dti = date_range(start="2016-10-21", end="2016-10-21", freq="BME")
167+
dti = date_range(start="2016-10-21", end="2016-10-21", freq="BME", unit=unit)
161168
result = dti.shift(1)
162169
tm.assert_index_equal(result, dti)

0 commit comments

Comments
 (0)