Skip to content

Commit 76f74d5

Browse files
authored
BUG: Index.get_slice_bounds does not accept datetime.date or tz naive datetime.datetimes (#35848)
1 parent 5227245 commit 76f74d5

File tree

5 files changed

+90
-5
lines changed

5 files changed

+90
-5
lines changed

doc/source/whatsnew/v1.2.0.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ Datetimelike
176176
- Bug in :attr:`DatetimeArray.date` where a ``ValueError`` would be raised with a read-only backing array (:issue:`33530`)
177177
- Bug in ``NaT`` comparisons failing to raise ``TypeError`` on invalid inequality comparisons (:issue:`35046`)
178178
- Bug in :class:`DateOffset` where attributes reconstructed from pickle files differ from original objects when input values exceed normal ranges (e.g months=12) (:issue:`34511`)
179-
-
179+
- Bug in :meth:`DatetimeIndex.get_slice_bound` where ``datetime.date`` objects were not accepted or naive :class:`Timestamp` with a tz-aware :class:`DatetimeIndex` (:issue:`35690`)
180+
- Bug in :meth:`DatetimeIndex.slice_locs` where ``datetime.date`` objects were not accepted (:issue:`34077`)
180181

181182
Timedelta
182183
^^^^^^^^^

pandas/core/indexes/datetimes.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ def get_loc(self, key, method=None, tolerance=None):
632632
raise KeyError(orig_key) from err
633633

634634
def _maybe_cast_for_get_loc(self, key) -> Timestamp:
635-
# needed to localize naive datetimes
635+
# needed to localize naive datetimes or dates (GH 35690)
636636
key = Timestamp(key)
637637
if key.tzinfo is None:
638638
key = key.tz_localize(self.tz)
@@ -677,8 +677,7 @@ def _maybe_cast_slice_bound(self, label, side: str, kind):
677677
if self._is_strictly_monotonic_decreasing and len(self) > 1:
678678
return upper if side == "left" else lower
679679
return lower if side == "left" else upper
680-
else:
681-
return label
680+
return self._maybe_cast_for_get_loc(label)
682681

683682
def _get_string_slice(self, key: str, use_lhs: bool = True, use_rhs: bool = True):
684683
freq = getattr(self, "freqstr", getattr(self, "inferred_freq", None))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import pytest
2+
3+
from pandas import Index
4+
5+
6+
class TestGetSliceBounds:
7+
@pytest.mark.parametrize("kind", ["getitem", "loc", None])
8+
@pytest.mark.parametrize("side, expected", [("left", 4), ("right", 5)])
9+
def test_get_slice_bounds_within(self, kind, side, expected):
10+
index = Index(list("abcdef"))
11+
result = index.get_slice_bound("e", kind=kind, side=side)
12+
assert result == expected
13+
14+
@pytest.mark.parametrize("kind", ["getitem", "loc", None])
15+
@pytest.mark.parametrize("side", ["left", "right"])
16+
@pytest.mark.parametrize(
17+
"data, bound, expected", [(list("abcdef"), "x", 6), (list("bcdefg"), "a", 0)],
18+
)
19+
def test_get_slice_bounds_outside(self, kind, side, expected, data, bound):
20+
index = Index(data)
21+
result = index.get_slice_bound(bound, kind=kind, side=side)
22+
assert result == expected
23+
24+
def test_get_slice_bounds_invalid_side(self):
25+
with pytest.raises(ValueError, match="Invalid value for side kwarg"):
26+
Index([]).get_slice_bound("a", kind=None, side="middle")

pandas/tests/indexes/datetimes/test_indexing.py

+41-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from pandas.errors import InvalidIndexError
77

88
import pandas as pd
9-
from pandas import DatetimeIndex, Index, Timestamp, date_range, notna
9+
from pandas import DatetimeIndex, Index, Timestamp, bdate_range, date_range, notna
1010
import pandas._testing as tm
1111

1212
from pandas.tseries.offsets import BDay, CDay
@@ -665,3 +665,43 @@ def test_get_value(self):
665665
with tm.assert_produces_warning(FutureWarning):
666666
result = dti.get_value(ser, key.to_datetime64())
667667
assert result == 7
668+
669+
670+
class TestGetSliceBounds:
671+
@pytest.mark.parametrize("box", [date, datetime, Timestamp])
672+
@pytest.mark.parametrize("kind", ["getitem", "loc", None])
673+
@pytest.mark.parametrize("side, expected", [("left", 4), ("right", 5)])
674+
def test_get_slice_bounds_datetime_within(
675+
self, box, kind, side, expected, tz_aware_fixture
676+
):
677+
# GH 35690
678+
index = bdate_range("2000-01-03", "2000-02-11").tz_localize(tz_aware_fixture)
679+
result = index.get_slice_bound(
680+
box(year=2000, month=1, day=7), kind=kind, side=side
681+
)
682+
assert result == expected
683+
684+
@pytest.mark.parametrize("box", [date, datetime, Timestamp])
685+
@pytest.mark.parametrize("kind", ["getitem", "loc", None])
686+
@pytest.mark.parametrize("side", ["left", "right"])
687+
@pytest.mark.parametrize("year, expected", [(1999, 0), (2020, 30)])
688+
def test_get_slice_bounds_datetime_outside(
689+
self, box, kind, side, year, expected, tz_aware_fixture
690+
):
691+
# GH 35690
692+
index = bdate_range("2000-01-03", "2000-02-11").tz_localize(tz_aware_fixture)
693+
result = index.get_slice_bound(
694+
box(year=year, month=1, day=7), kind=kind, side=side
695+
)
696+
assert result == expected
697+
698+
@pytest.mark.parametrize("box", [date, datetime, Timestamp])
699+
@pytest.mark.parametrize("kind", ["getitem", "loc", None])
700+
def test_slice_datetime_locs(self, box, kind, tz_aware_fixture):
701+
# GH 34077
702+
index = DatetimeIndex(["2010-01-01", "2010-01-03"]).tz_localize(
703+
tz_aware_fixture
704+
)
705+
result = index.slice_locs(box(2010, 1, 1), box(2010, 1, 2))
706+
expected = (0, 1)
707+
assert result == expected

pandas/tests/indexes/test_numeric.py

+19
Original file line numberDiff line numberDiff line change
@@ -679,3 +679,22 @@ def test_float64_index_difference():
679679

680680
result = string_index.difference(float_index)
681681
tm.assert_index_equal(result, string_index)
682+
683+
684+
class TestGetSliceBounds:
685+
@pytest.mark.parametrize("kind", ["getitem", "loc", None])
686+
@pytest.mark.parametrize("side, expected", [("left", 4), ("right", 5)])
687+
def test_get_slice_bounds_within(self, kind, side, expected):
688+
index = Index(range(6))
689+
result = index.get_slice_bound(4, kind=kind, side=side)
690+
assert result == expected
691+
692+
@pytest.mark.parametrize("kind", ["getitem", "loc", None])
693+
@pytest.mark.parametrize("side", ["left", "right"])
694+
@pytest.mark.parametrize(
695+
"bound, expected", [(-1, 0), (10, 6)],
696+
)
697+
def test_get_slice_bounds_outside(self, kind, side, expected, bound):
698+
index = Index(range(6))
699+
result = index.get_slice_bound(bound, kind=kind, side=side)
700+
assert result == expected

0 commit comments

Comments
 (0)