diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index c9347b88f2072..e2b851d6ea81e 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -639,6 +639,7 @@ Indexing - Bug in :meth:`DataFrame.loc` raising ``TypeError`` when non-integer slice was given to select values from :class:`MultiIndex` (:issue:`25165`, :issue:`24263`) - Bug in :meth:`Series.at` returning :class:`Series` with one element instead of scalar when index is a :class:`MultiIndex` with one level (:issue:`38053`) - Bug in :meth:`DataFrame.loc` returning and assigning elements in wrong order when indexer is differently ordered than the :class:`MultiIndex` to filter (:issue:`31330`, :issue:`34603`) +- Bug in :meth:`DataFrame.loc` raising ``KeyError`` for list-like indexers with string slices for :class:`DatetimeIndex` (:issue:`27180`) - Bug in :meth:`DataFrame.loc` and :meth:`DataFrame.__getitem__` raising ``KeyError`` when columns were :class:`MultiIndex` with only one level (:issue:`29749`) - Bug in :meth:`Series.__getitem__` and :meth:`DataFrame.__getitem__` raising blank ``KeyError`` without missing keys for :class:`IntervalIndex` (:issue:`27365`) - Bug in setting a new label on a :class:`DataFrame` or :class:`Series` with a :class:`CategoricalIndex` incorrectly raising ``TypeError`` when the new label is not among the index's categories (:issue:`38098`) diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 8329c41a74596..80357561b32e9 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -819,6 +819,25 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None): # -------------------------------------------------------------------- + def _convert_listlike_indexer(self, key): + if not isinstance(key, list): + # There are no slices, so we can dispatch back + return super()._convert_listlike_indexer(key) + + new_indexer = [] + positions = list(range(len(self))) + try: + for k in key: + # Convert slices to list of integers + indexer = positions[self.get_loc(k)] + if not isinstance(indexer, list): + indexer = [indexer] + new_indexer.extend(indexer) + except KeyError: + # Dispatch to base method for handling of KeyErrors + return super()._convert_listlike_indexer(key) + return np.array(new_indexer), key + @property def inferred_type(self) -> str: # b/c datetime is represented as microseconds since the epoch, make diff --git a/pandas/tests/indexing/test_datetime.py b/pandas/tests/indexing/test_datetime.py index d00fe58265a2e..9bf66cfd02942 100644 --- a/pandas/tests/indexing/test_datetime.py +++ b/pandas/tests/indexing/test_datetime.py @@ -231,3 +231,21 @@ def test_loc_setitem_with_existing_dst(self): dtype=object, ) tm.assert_frame_equal(result, expected) + + @pytest.mark.parametrize( + "indexer", [["2001-01", "2001-01-30"], ["2001-01", Timestamp("2001-01-30")]] + ) + def test_loc_getitem_partial_strings_in_list(self, indexer): + # GH#27180 + ser = Series(1, index=date_range("2001-01-29", periods=60)) + result = ser.loc[indexer] + expected = Series( + 1, + index=[ + Timestamp("2001-01-29"), + Timestamp("2001-01-30"), + Timestamp("2001-01-31"), + Timestamp("2001-01-30"), + ], + ) + tm.assert_series_equal(result, expected)