diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index d0644fbb7ef54..3411be475ef11 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -144,7 +144,7 @@ Interval Indexing ^^^^^^^^ - Bug in slicing on a :class:`DatetimeIndex` with a partial-timestamp dropping high-resolution indices near the end of a year, quarter, or month (:issue:`31064`) -- +- Bug in :meth:`PeriodIndex.get_loc` treating higher-resolution strings differently from :meth:`PeriodIndex.get_value` (:issue:`31172`) - Missing diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index 2a40f4a6f6239..fe6c1ba808f9a 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -486,7 +486,7 @@ def get_value(self, series, key): try: loc = self._get_string_slice(key) return series[loc] - except (TypeError, ValueError): + except (TypeError, ValueError, OverflowError): pass asdt, reso = parse_time_string(key, self.freq) @@ -567,18 +567,34 @@ def get_loc(self, key, method=None, tolerance=None): """ if isinstance(key, str): + try: - return self._get_string_slice(key) - except (TypeError, KeyError, ValueError, OverflowError): + loc = self._get_string_slice(key) + return loc + except (TypeError, ValueError): pass try: asdt, reso = parse_time_string(key, self.freq) - key = asdt except DateParseError: # A string with invalid format raise KeyError(f"Cannot interpret '{key}' as period") + grp = resolution.Resolution.get_freq_group(reso) + freqn = resolution.get_freq_group(self.freq) + + # _get_string_slice will handle cases where grp < freqn + assert grp >= freqn + + if grp == freqn: + key = Period(asdt, freq=self.freq) + loc = self.get_loc(key, method=method, tolerance=tolerance) + return loc + elif method is None: + raise KeyError(key) + else: + key = asdt + elif is_integer(key): # Period constructor will cast to string, which we dont want raise KeyError(key) diff --git a/pandas/tests/indexes/period/test_indexing.py b/pandas/tests/indexes/period/test_indexing.py index 1e3160980e8bb..4c1438915ab33 100644 --- a/pandas/tests/indexes/period/test_indexing.py +++ b/pandas/tests/indexes/period/test_indexing.py @@ -518,12 +518,20 @@ def test_contains(self): ps0 = [p0, p1, p2] idx0 = pd.PeriodIndex(ps0) + ser = pd.Series(range(6, 9), index=idx0) for p in ps0: assert p in idx0 assert str(p) in idx0 - assert "2017-09-01 00:00:01" in idx0 + # GH#31172 + # Higher-resolution period-like are _not_ considered as contained + key = "2017-09-01 00:00:01" + assert key not in idx0 + with pytest.raises(KeyError, match=key): + idx0.get_loc(key) + with pytest.raises(KeyError, match=key): + idx0.get_value(ser, key) assert "2017-09" in idx0