Skip to content

Commit 8a33050

Browse files
authored
BUG: PeriodIndex.is_monotonic with leading NaT (pandas-dev#31437)
1 parent db4da03 commit 8a33050

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

doc/source/whatsnew/v1.1.0.rst

+2
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ Indexing
149149
- 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`)
150150
- Bug in :meth:`PeriodIndex.get_loc` treating higher-resolution strings differently from :meth:`PeriodIndex.get_value` (:issue:`31172`)
151151
- Bug in :meth:`Series.at` and :meth:`DataFrame.at` not matching ``.loc`` behavior when looking up an integer in a :class:`Float64Index` (:issue:`31329`)
152+
- Bug in :meth:`PeriodIndex.is_monotonic` incorrectly returning ``True`` when containing leading ``NaT`` entries (:issue:`31437`)
153+
-
152154

153155
Missing
154156
^^^^^^^

pandas/_libs/index.pyx

+1-2
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,7 @@ cdef class PeriodEngine(Int64Engine):
514514
return super(PeriodEngine, self).vgetter().view("i8")
515515

516516
cdef _call_monotonic(self, values):
517-
# super(...) pattern doesn't seem to work with `cdef`
518-
return Int64Engine._call_monotonic(self, values.view('i8'))
517+
return algos.is_monotonic(values, timelike=True)
519518

520519
def get_indexer(self, values):
521520
cdef:

pandas/tests/indexes/period/test_period.py

+41
Original file line numberDiff line numberDiff line change
@@ -662,3 +662,44 @@ def test_maybe_convert_timedelta():
662662
msg = r"Input has different freq=B from PeriodIndex\(freq=D\)"
663663
with pytest.raises(ValueError, match=msg):
664664
pi._maybe_convert_timedelta(offset)
665+
666+
667+
def test_is_monotonic_with_nat():
668+
# GH#31437
669+
# PeriodIndex.is_monotonic should behave analogously to DatetimeIndex,
670+
# in particular never be monotonic when we have NaT
671+
dti = pd.date_range("2016-01-01", periods=3)
672+
pi = dti.to_period("D")
673+
tdi = pd.Index(dti.view("timedelta64[ns]"))
674+
675+
for obj in [pi, pi._engine, dti, dti._engine, tdi, tdi._engine]:
676+
if isinstance(obj, pd.Index):
677+
# i.e. not Engines
678+
assert obj.is_monotonic
679+
assert obj.is_monotonic_increasing
680+
assert not obj.is_monotonic_decreasing
681+
assert obj.is_unique
682+
683+
dti1 = dti.insert(0, pd.NaT)
684+
pi1 = dti1.to_period("D")
685+
tdi1 = pd.Index(dti1.view("timedelta64[ns]"))
686+
687+
for obj in [pi1, pi1._engine, dti1, dti1._engine, tdi1, tdi1._engine]:
688+
if isinstance(obj, pd.Index):
689+
# i.e. not Engines
690+
assert not obj.is_monotonic
691+
assert not obj.is_monotonic_increasing
692+
assert not obj.is_monotonic_decreasing
693+
assert obj.is_unique
694+
695+
dti2 = dti.insert(3, pd.NaT)
696+
pi2 = dti2.to_period("H")
697+
tdi2 = pd.Index(dti2.view("timedelta64[ns]"))
698+
699+
for obj in [pi2, pi2._engine, dti2, dti2._engine, tdi2, tdi2._engine]:
700+
if isinstance(obj, pd.Index):
701+
# i.e. not Engines
702+
assert not obj.is_monotonic
703+
assert not obj.is_monotonic_increasing
704+
assert not obj.is_monotonic_decreasing
705+
assert obj.is_unique

pandas/tests/reductions/test_reductions.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,8 @@ def test_minmax_period(self):
440440

441441
# monotonic
442442
idx1 = pd.PeriodIndex([NaT, "2011-01-01", "2011-01-02", "2011-01-03"], freq="D")
443-
assert idx1.is_monotonic
443+
assert not idx1.is_monotonic
444+
assert idx1[1:].is_monotonic
444445

445446
# non-monotonic
446447
idx2 = pd.PeriodIndex(

0 commit comments

Comments
 (0)