diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index c3377db457270..b05c296e34e2f 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -944,6 +944,7 @@ Datetimelike ^^^^^^^^^^^^ - Bug in :attr:`is_year_start` where a DateTimeIndex constructed via a date_range with frequency 'MS' wouldn't have the correct year or quarter start attributes (:issue:`57377`) - Bug in :class:`DataFrame` raising ``ValueError`` when ``dtype`` is ``timedelta64`` and ``data`` is a list containing ``None`` (:issue:`60064`) +- Bug in :class:`DatetimeIndex` returning KeyError for out of range, failing to return empty slice when the resolution is greater than the current datetime objects. (:issue:`25803`) - Bug in :class:`Timestamp` constructor failing to raise when ``tz=None`` is explicitly specified in conjunction with timezone-aware ``tzinfo`` or data (:issue:`48688`) - Bug in :class:`Timestamp` constructor failing to raise when given a ``np.datetime64`` object with non-standard unit (:issue:`25611`) - Bug in :func:`date_range` where the last valid timestamp would sometimes not be produced (:issue:`56134`) diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 7e6461f0fab5e..368c2aec78f01 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -317,15 +317,8 @@ def _partial_date_slice( unbox = self._data._unbox if self.is_monotonic_increasing: - if len(self) and ( - (t1 < self[0] and t2 < self[0]) or (t1 > self[-1] and t2 > self[-1]) - ): - # we are out of range - raise KeyError - - # TODO: does this depend on being monotonic _increasing_? - - # a monotonic (sorted) series can be sliced + # a monotonic (sorted) series can be searched in ologn + # if date is not found, the empty slice will be returned left = vals.searchsorted(unbox(t1), side="left") right = vals.searchsorted(unbox(t2), side="right") return slice(left, right) diff --git a/pandas/tests/indexes/datetimes/test_partial_slicing.py b/pandas/tests/indexes/datetimes/test_partial_slicing.py index 94175a56f1c4a..3047f1f29ff3d 100644 --- a/pandas/tests/indexes/datetimes/test_partial_slicing.py +++ b/pandas/tests/indexes/datetimes/test_partial_slicing.py @@ -247,8 +247,16 @@ def test_partial_slice_second_precision(self): tm.assert_series_equal(s["2005-1-1 00:01:00"], s.iloc[10:]) assert s[Timestamp("2005-1-1 00:00:59.999990")] == s.iloc[0] - with pytest.raises(KeyError, match="2005-1-1 00:00:00"): - s["2005-1-1 00:00:00"] + tm.assert_series_equal(s["2005-1-1 00:00:00"], s.iloc[0:0]) + + def test_partial_slice_higher_precision_empty(self): + # GH25803 + s = Series( + [1, 2, 3], + DatetimeIndex(["2018-01-01T01:01", "2018-02-02T01:01", "2018-02-02T02:02"]), + ) + tm.assert_series_equal(s.loc["2018-03-03"], s.iloc[0:0]) + assert s.loc["2018-03-03"].size == 0 def test_partial_slicing_dataframe(self): # GH14856 diff --git a/pandas/tests/indexes/period/test_indexing.py b/pandas/tests/indexes/period/test_indexing.py index 75382cb735288..0b59c39fd46ee 100644 --- a/pandas/tests/indexes/period/test_indexing.py +++ b/pandas/tests/indexes/period/test_indexing.py @@ -112,8 +112,8 @@ def test_getitem_partial(self): rng = period_range("2007-01", periods=50, freq="M") ts = Series(np.random.default_rng(2).standard_normal(len(rng)), rng) - with pytest.raises(KeyError, match=r"^'2006'$"): - ts["2006"] + # GH 25803 + assert len(ts["2006"]) == 0 result = ts["2008"] assert (result.index.year == 2008).all()