Repository: pandas-dev/pandas

Issue:
BUG: Timedelta.__floordiv__ - need historical context
```
>>> pd.Timedelta(days=3, hours=4) // np.datetime64('NaT')
-1
```

`Timedelta.__floordiv__` and `__rfloordiv__` begin with:

```
        if hasattr(other, 'dtype'):
            # work with i8
            other = other.astype('m8[ns]').astype('i8')
```

I _think_ this is a historical artifact from early numpy versions, because in core.ops there is a comment:
```
            # time delta division -> unit less
            # integer gets converted to timedelta in np < 1.6
            if ((self.is_timedelta_lhs and self.is_timedelta_rhs) and
                    not self.is_integer_rhs and not self.is_integer_lhs and
                    self.name in ('__div__', '__truediv__')):
```

Before I try to fix `Timedelta.__floordiv__` can someone knowledgeable weight in on why all dtypes are being converted to i8?


Discussion:

Resolving patch:
diff --git a/pandas/core/ops.py b/pandas/core/ops.py
--- a/pandas/core/ops.py
+++ b/pandas/core/ops.py
@@ -425,7 +425,7 @@ def _validate_timedelta(self, name):
             # 2 timedeltas
             if name not in ('__div__', '__rdiv__', '__truediv__',
                             '__rtruediv__', '__add__', '__radd__', '__sub__',
-                            '__rsub__'):
+                            '__rsub__', '__floordiv__', '__rfloordiv__'):
                 raise TypeError("can only operate on a timedeltas for addition"
                                 ", subtraction, and division, but the operator"
                                 " [{name}] was passed".format(name=name))
@@ -629,7 +629,9 @@ def _offset(lvalues, rvalues):
             # integer gets converted to timedelta in np < 1.6
             if ((self.is_timedelta_lhs and self.is_timedelta_rhs) and
                     not self.is_integer_rhs and not self.is_integer_lhs and
-                    self.name in ('__div__', '__truediv__')):
+                    self.name in ('__div__', '__rdiv__',
+                                  '__truediv__', '__rtruediv__',
+                                  '__floordiv__', '__rfloordiv__')):
                 self.dtype = 'float64'
                 self.fill_value = np.nan
                 lvalues = lvalues.astype(np.float64)


Test patch:
diff --git a/pandas/tests/series/test_operators.py b/pandas/tests/series/test_operators.py
--- a/pandas/tests/series/test_operators.py
+++ b/pandas/tests/series/test_operators.py
@@ -977,9 +977,7 @@ def test_operators_timedelta64_with_timedelta(self, scalar_td):
 
     @pytest.mark.parametrize('scalar_td', [
         timedelta(minutes=5, seconds=4),
-        pytest.param(Timedelta('5m4s'),
-                     marks=pytest.mark.xfail(reason="Timedelta.__floordiv__ "
-                                                    "bug GH#18846")),
+        Timedelta('5m4s'),
         Timedelta('5m4s').to_timedelta64()])
     def test_operators_timedelta64_with_timedelta_invalid(self, scalar_td):
         td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
@@ -993,15 +991,53 @@ def test_operators_timedelta64_with_timedelta_invalid(self, scalar_td):
             td1 * scalar_td
         with tm.assert_raises_regex(TypeError, pattern):
             scalar_td * td1
-        with tm.assert_raises_regex(TypeError, pattern):
-            td1 // scalar_td
-        with tm.assert_raises_regex(TypeError, pattern):
-            scalar_td // td1
         with tm.assert_raises_regex(TypeError, pattern):
             scalar_td ** td1
         with tm.assert_raises_regex(TypeError, pattern):
             td1 ** scalar_td
 
+    @pytest.mark.parametrize('scalar_td', [
+        timedelta(minutes=5, seconds=4),
+        pytest.param(Timedelta('5m4s'),
+                     marks=pytest.mark.xfail(reason="Timedelta.__floordiv__ "
+                                                    "bug GH#18846")),
+        Timedelta('5m4s').to_timedelta64()])
+    def test_timedelta_rfloordiv(self, scalar_td):
+        # GH#18831
+        td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
+        td1.iloc[2] = np.nan
+        result = scalar_td // td1
+        expected = Series([1, 1, np.nan])
+        tm.assert_series_equal(result, expected)
+
+    @pytest.mark.parametrize('scalar_td', [
+        timedelta(minutes=5, seconds=4),
+        Timedelta('5m4s'),
+        Timedelta('5m4s').to_timedelta64()])
+    def test_timedelta_rfloordiv_explicit(self, scalar_td):
+        # GH#18831
+        td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
+        td1.iloc[2] = np.nan
+
+        # We can test __rfloordiv__ using this syntax,
+        # see `test_timedelta_rfloordiv`
+        result = td1.__rfloordiv__(scalar_td)
+        expected = Series([1, 1, np.nan])
+        tm.assert_series_equal(result, expected)
+
+    @pytest.mark.parametrize('scalar_td', [
+        timedelta(minutes=5, seconds=4),
+        Timedelta('5m4s'),
+        Timedelta('5m4s').to_timedelta64()])
+    def test_timedelta_floordiv(self, scalar_td):
+        # GH#18831
+        td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
+        td1.iloc[2] = np.nan
+
+        result = td1 // scalar_td
+        expected = Series([0, 0, np.nan])
+        tm.assert_series_equal(result, expected)
+
 
 class TestDatetimeSeriesArithmetic(object):
     @pytest.mark.parametrize(