Repository: modin-project/modin

Issue:
sliceing with datetimeindex is not working as expected

### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: Ubuntu 18.04
- **Modin installed from (source or binary)**:pypi
- **Modin version**:0.6.0
- **Python version**:3.6.8
- **Exact command to reproduce**:

### Describe the problem
with modin:
```py
import modin.pandas as pd
df = pd.DataFrame(data={'data': range(10)}, index=pd.date_range('2017/1/4',periods=10))
print(df['2017-01-06':'2017-01-09'])
```
 I got this:
```sh
            data
2017-01-04     0
2017-01-05     1
2017-01-06     2
2017-01-07     3
2017-01-08     4
2017-01-09     5
```

but  with pandas:
```py
import pandas as pd
df = pd.DataFrame(data={'data': range(10)}, index=pd.date_range('2017/1/4',periods=10))
print(df['2017-01-06':'2017-01-09'])
```
 I got this:
```sh
            data
2017-01-06     2
2017-01-07     3
2017-01-08     4
2017-01-09     5

```



Discussion:
Hi @dwSun, thanks for posting! 

I can reproduce the bug, and it looks like an issue with how we handle slices that don't contain numeric indices.

```python
df[2:6] # works
```

I will dig into this before the next release, thanks again for posting!

Resolving patch:
diff --git a/modin/pandas/base.py b/modin/pandas/base.py
--- a/modin/pandas/base.py
+++ b/modin/pandas/base.py
@@ -3192,23 +3192,47 @@ def __getitem__(self, key):
     def _getitem_slice(self, key):
         # If there is no step, we can fasttrack the codepath to use existing logic from
         # head and tail, which is already pretty fast.
-        if key.step is None:
+        if (
+            key.step is None
+            and (isinstance(key.start, int) or key.start is None)
+            and (isinstance(key.stop, int) or key.stop is None)
+        ):
             if key.start is None and key.stop is None:
                 return self.copy()
 
             def compute_offset(value):
-                return value - len(self) if value >= 0 else value
+                return (
+                    value - len(self)
+                    if value > 0
+                    else value
+                    if value != 0
+                    else len(self)
+                )
 
             # Head is a negative number, Tail is a positive number
             if key.start is None:
                 return self.head(compute_offset(key.stop))
             elif key.stop is None:
-                return self.tail(-compute_offset(key.start))
-            return self.head(compute_offset(key.stop)).tail(-compute_offset(key.start))
+                print(compute_offset(-key.start))
+                return self.tail(compute_offset(-key.start))
+            return self.head(compute_offset(key.stop)).tail(compute_offset(-key.start))
         # We convert to a RangeIndex because getitem_row_array is expecting a list
         # of indices, and RangeIndex will give us the exact indices of each boolean
         # requested.
-        key = pandas.RangeIndex(len(self.index))[key]
+        if isinstance(key.start, int) and isinstance(key.stop, int):
+            key = pandas.RangeIndex(len(self.index))[key]
+        else:
+            # To handle this case correctly, we let pandas compute the indices by
+            # creating a MultiIndex ("a", "b") such that "a" is the original index and
+            # "b" is the Range of numeric indices for each. Then we apply the slice to
+            # the original index (named "a"), then extract the index values (named "b")
+            # and pass that along to be sliced in the actual data. This also serves as a
+            # validation that the input slice is usable and correct.
+            key = pandas.DataFrame(
+                index=pandas.MultiIndex.from_arrays(
+                    [self.index, pandas.RangeIndex(len(self.index))], names=["a", "b"]
+                )
+            )[key].index.get_level_values("b")
         return self.__constructor__(
             query_compiler=self._query_compiler.getitem_row_array(key)
         )


Test patch:
diff --git a/modin/pandas/test/test_dataframe.py b/modin/pandas/test/test_dataframe.py
--- a/modin/pandas/test/test_dataframe.py
+++ b/modin/pandas/test/test_dataframe.py
@@ -4866,6 +4866,22 @@ def test___getitem__(self, data):
         pd_col = pandas_df[key]
         df_equals(pd_col, modin_col)
 
+        slices = [
+            (None, -1),
+            (-1, None),
+            (1, 2),
+            (1, None),
+            (None, 1),
+            (1, -1),
+            (-3, -1),
+            (1, -1, 2),
+        ]
+
+        # slice test
+        for slice_param in slices:
+            s = slice(*slice_param)
+            df_equals(modin_df[s], pandas_df[s])
+
         # Test empty
         df_equals(pd.DataFrame([])[:10], pandas.DataFrame([])[:10])
 
@@ -4898,6 +4914,15 @@ def test_getitem_empty_mask(self):
             pandas_data[[False for _ in modin_data.index]],
         )
 
+    def test_getitem_datetime_slice(self):
+        data = {"data": range(1000)}
+        index = pd.date_range("2017/1/4", periods=1000)
+        modin_df = pd.DataFrame(data=data, index=index)
+        pandas_df = pandas.DataFrame(data=data, index=index)
+
+        s = slice("2017-01-06", "2017-01-09")
+        df_equals(modin_df[s], pandas_df[s])
+
     @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
     def test___getattr__(self, request, data):
         modin_df = pd.DataFrame(data)
diff --git a/modin/pandas/test/test_series.py b/modin/pandas/test/test_series.py
--- a/modin/pandas/test/test_series.py
+++ b/modin/pandas/test/test_series.py
@@ -1684,6 +1684,7 @@ def test_loc(data):
     modin_series, pandas_series = create_test_series(data)
     for v in modin_series.index:
         df_equals(modin_series.loc[v], pandas_series.loc[v])
+        print(v)
         df_equals(modin_series.loc[v:], pandas_series.loc[v:])
 
     indices = [True if i % 3 == 0 else False for i in range(len(modin_series.index))]