Repository: pandas-dev/pandas

Issue:
ERR: better error message on non-sorted input with .truncate
xref #17295

This is correct, but since the doc-string says sorted, we should check this and give a nicer message. (not that should check both ``.is_monotonic_increasing`` and ``decreasing`` cases, and confirm that the before/after match)
```
In [8]: rng2 = pd.date_range('2011-01-01', '2012-01-01', freq='W')
   ...: ts2 = pd.Series(np.random.randn(len(rng2)), index=rng2)

In [9]: ts2.truncate(before='2011-11', after='2011-12')
Out[9]: 
2011-11-06    0.144986
2011-11-13   -1.823425
2011-11-20    1.742315
2011-11-27    0.311337
Freq: W-SUN, dtype: float64

In [10]: ts2.sort_values(ascending=False).truncate(before='2011-11', after='2011-12')
KeyError: Timestamp('2011-11-01 00:00:00')
```


Discussion:
cc @reidy-p 
@jreback thanks, I'll take a look.

Resolving patch:
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -6338,6 +6338,11 @@ def truncate(self, before=None, after=None, axis=None, copy=True):
         axis = self._get_axis_number(axis)
         ax = self._get_axis(axis)
 
+        # GH 17935
+        # Check that index is sorted
+        if not ax.is_monotonic_increasing and not ax.is_monotonic_decreasing:
+            raise ValueError("truncate requires a sorted index")
+
         # if we have a date index, convert to dates, otherwise
         # treat like a slice
         if ax.is_all_dates:


Test patch:
diff --git a/pandas/tests/frame/test_timeseries.py b/pandas/tests/frame/test_timeseries.py
--- a/pandas/tests/frame/test_timeseries.py
+++ b/pandas/tests/frame/test_timeseries.py
@@ -377,6 +377,33 @@ def test_truncate_copy(self):
         truncated.values[:] = 5.
         assert not (self.tsframe.values[5:11] == 5).any()
 
+    def test_truncate_nonsortedindex(self):
+        # GH 17935
+
+        df = pd.DataFrame({'A': ['a', 'b', 'c', 'd', 'e']},
+                          index=[5, 3, 2, 9, 0])
+        with tm.assert_raises_regex(ValueError,
+                                    'truncate requires a sorted index'):
+            df.truncate(before=3, after=9)
+
+        rng = pd.date_range('2011-01-01', '2012-01-01', freq='W')
+        ts = pd.DataFrame({'A': np.random.randn(len(rng)),
+                           'B': np.random.randn(len(rng))},
+                          index=rng)
+        with tm.assert_raises_regex(ValueError,
+                                    'truncate requires a sorted index'):
+            ts.sort_values('A', ascending=False).truncate(before='2011-11',
+                                                          after='2011-12')
+
+        df = pd.DataFrame({3: np.random.randn(5),
+                           20: np.random.randn(5),
+                           2: np.random.randn(5),
+                           0: np.random.randn(5)},
+                          columns=[3, 20, 2, 0])
+        with tm.assert_raises_regex(ValueError,
+                                    'truncate requires a sorted index'):
+            df.truncate(before=2, after=20, axis=1)
+
     def test_asfreq(self):
         offset_monthly = self.tsframe.asfreq(offsets.BMonthEnd())
         rule_monthly = self.tsframe.asfreq('BM')
diff --git a/pandas/tests/series/test_period.py b/pandas/tests/series/test_period.py
--- a/pandas/tests/series/test_period.py
+++ b/pandas/tests/series/test_period.py
@@ -272,10 +272,9 @@ def test_truncate(self):
             pd.Period('2017-09-03')
         ])
         series2 = pd.Series([1, 2, 3], index=idx2)
-        result2 = series2.truncate(after='2017-09-02')
+        result2 = series2.sort_index().truncate(after='2017-09-02')
 
         expected_idx2 = pd.PeriodIndex([
-            pd.Period('2017-09-03'),
             pd.Period('2017-09-02')
         ])
-        tm.assert_series_equal(result2, pd.Series([1, 2], index=expected_idx2))
+        tm.assert_series_equal(result2, pd.Series([2], index=expected_idx2))
diff --git a/pandas/tests/series/test_timeseries.py b/pandas/tests/series/test_timeseries.py
--- a/pandas/tests/series/test_timeseries.py
+++ b/pandas/tests/series/test_timeseries.py
@@ -236,6 +236,22 @@ def test_truncate(self):
                       before=self.ts.index[-1] + offset,
                       after=self.ts.index[0] - offset)
 
+    def test_truncate_nonsortedindex(self):
+        # GH 17935
+
+        s = pd.Series(['a', 'b', 'c', 'd', 'e'],
+                      index=[5, 3, 2, 9, 0])
+        with tm.assert_raises_regex(ValueError,
+                                    'truncate requires a sorted index'):
+            s.truncate(before=3, after=9)
+
+        rng = pd.date_range('2011-01-01', '2012-01-01', freq='W')
+        ts = pd.Series(np.random.randn(len(rng)), index=rng)
+        with tm.assert_raises_regex(ValueError,
+                                    'truncate requires a sorted index'):
+            ts.sort_values(ascending=False).truncate(before='2011-11',
+                                                     after='2011-12')
+
     def test_asfreq(self):
         ts = Series([0., 1., 2.], index=[datetime(2009, 10, 30), datetime(
             2009, 11, 30), datetime(2009, 12, 31)])