Repository: pandas-dev/pandas

Issue:
Index._maybe_cast_slice_bound switched meaning of left/right
'left' and 'right' changed meaning in `DatetimeIndex._maybe_cast_slice_bound`.  Was this intentional?
### Pandas 0.18

``` python
In [1]: import pandas as pd

In [2]: index = pd.DatetimeIndex(freq='1H', periods=0, end='2015')

In [3]: index._maybe_cast_slice_bound('2015-01-02', 'right', 'loc')
Out[3]: Timestamp('2015-01-02 23:59:59.999999999')

In [4]: index._maybe_cast_slice_bound('2015-01-02', 'left', 'loc')
Out[4]: Timestamp('2015-01-02 00:00:00')
```
### Pandas 0.19

``` python
In [1]: import pandas as pd

In [2]: index = pd.DatetimeIndex(freq='1H', periods=0, end='2015')

In [3]: index._maybe_cast_slice_bound('2015-01-02', 'right', 'loc')
Out[3]: Timestamp('2015-01-02 00:00:00')

In [4]: index._maybe_cast_slice_bound('2015-01-02', 'left', 'loc')
Out[4]: Timestamp('2015-01-02 23:59:59.999999999')
```



Discussion:
This is related to https://github.com/pydata/pandas/pull/14317

But the reason this is now different, is because the index thinks it is monotonic decreasing:

```
In [20]: index = pd.DatetimeIndex(freq='1H', periods=0, end='2015')

In [21]: index.is_monotonic_decreasing
Out[21]: True
```

Yeah, maybe should reverse this conditional and make `is_monotonic_increasing` the assumption for a length 0 index?

https://github.com/pydata/pandas/pull/14317/files#diff-23ecb29e7ceba52109a365e447400d2eR1454

Interestingly it is both:

``` python
In [4]: index
Out[4]: DatetimeIndex([], dtype='datetime64[ns]', freq='H')

In [5]: index.is_monotonic_increasing
Out[5]: True

In [6]: index.is_monotonic_decreasing
Out[6]: True
```

yeah I think this needs an adjustment to non-pick the decreasing case when both are true. (or just special case on empty).


Resolving patch:
diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py
--- a/pandas/tseries/index.py
+++ b/pandas/tseries/index.py
@@ -1453,8 +1453,9 @@ def _maybe_cast_slice_bound(self, label, side, kind):
             # lower, upper form the half-open interval:
             #   [parsed, parsed + 1 freq)
             # because label may be passed to searchsorted
-            # the bounds need swapped if index is reverse sorted
-            if self.is_monotonic_decreasing:
+            # the bounds need swapped if index is reverse sorted and has a
+            # length (is_monotonic_decreasing gives True for empty index)
+            if self.is_monotonic_decreasing and len(self):
                 return upper if side == 'left' else lower
             return lower if side == 'left' else upper
         else:


Test patch:
diff --git a/pandas/tseries/tests/test_timeseries.py b/pandas/tseries/tests/test_timeseries.py
--- a/pandas/tseries/tests/test_timeseries.py
+++ b/pandas/tseries/tests/test_timeseries.py
@@ -3911,6 +3911,18 @@ def test_slice_with_zero_step_raises(self):
         self.assertRaisesRegexp(ValueError, 'slice step cannot be zero',
                                 lambda: ts.ix[::0])
 
+    def test_slice_bounds_empty(self):
+        # GH 14354
+        empty_idx = DatetimeIndex(freq='1H', periods=0, end='2015')
+
+        right = empty_idx._maybe_cast_slice_bound('2015-01-02', 'right', 'loc')
+        exp = Timestamp('2015-01-02 23:59:59.999999999')
+        self.assertEqual(right, exp)
+
+        left = empty_idx._maybe_cast_slice_bound('2015-01-02', 'left', 'loc')
+        exp = Timestamp('2015-01-02 00:00:00')
+        self.assertEqual(left, exp)
+
 
 class TestDatetime64(tm.TestCase):
     """