Repository: numpy/numpy
Pull request: BUG: datetime64/timedelta64 comparisons return NotImplemented
Closes #17017

Problem statement:
BUG: datetime64, timedelta64 comparisons do not return NotImplemented
I expected datetime64 and timedelta64 comparison methods to return NotImplemented when operating with pd.NaT, which has `__array_priority__ = 100`.


```
import numpy as np
import pandas as pd

ts = np.datetime64("now", "ns")
td = np.timedelta64(0, "ns")

assert pd.NaT.__array_priority__ == 100

>>> ts.__lt__(pd.NaT)
array(False)

>>> td.__lt__(pd.NaT)
array(False)
```

Hints from issue discussion:
@jbrockmendel hmm, the code is a bit weird. but effectively will do:
```
def __lt__(self, other):
    arr = np.asarray(self)
    return arr < other
```
I.e. it seems like it should be deferring to the pandas `NaT`, but after converting itself into an array.  Is it possible that this is what happens, but still problematic?
That said, I do think it would be fair to defer right away, although this is a common (and sometimes buggy) path currently for when the other object is a scalar not known to NumPy.
> Is it possible that this is what happens, but still problematic?

Seems like a reasonable explanation.  For some reason comparing against Timestamp works as expected
Returning an array instead of a scalar here shows that this is all slightly weird... Since its the right thing to do for pandas, but guessing that we should convert that array to a scalar seems only half right (although possibly more right than the current result). OTOH, I guess it doesn't matter too much...

Commit message: Update numpy/core/src/multiarray/scalartypes.c.src

Co-authored-by: Sebastian Berg <sebastian@sipsolutions.net>

Patch to review:
diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src
index bddfbf536e84..e9fb8f10dee2 100644
--- a/numpy/core/src/multiarray/scalartypes.c.src
+++ b/numpy/core/src/multiarray/scalartypes.c.src
@@ -1059,6 +1059,7 @@ static PyObject *
 gentype_richcompare(PyObject *self, PyObject *other, int cmp_op)
 {
     PyObject *arr, *ret;
+    double self_prio, other_prio;
 
     /*
      * If the other object is None, False is always right. This avoids
@@ -1078,6 +1079,8 @@ gentype_richcompare(PyObject *self, PyObject *other, int cmp_op)
         }
     }
 
+   RICHCMP_GIVE_UP_IF_NEEDED(self, other);
+
     arr = PyArray_FromScalar(self, NULL);
     if (arr == NULL) {
         return NULL;
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index 948911f1c676..2b56d482475a 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -2529,3 +2529,23 @@ def test_non_ascii(self):
 
         dt = np.datetime64('2000', '5μs')
         assert np.datetime_data(dt.dtype) == ('us', 5)
+
+
+def test_comparisons_return_not_implemented():
+    # GH#17017
+
+    class custom:
+        __array_priority__ = 10000
+
+    obj = custom()
+
+    dt = np.datetime64('2000', 'ns')
+    td = dt - dt
+
+    for item in [dt, td]:
+        assert item.__eq__(obj) is NotImplemented
+        assert item.__ne__(obj) is NotImplemented
+        assert item.__le__(obj) is NotImplemented
+        assert item.__lt__(obj) is NotImplemented
+        assert item.__ge__(obj) is NotImplemented
+        assert item.__gt__(obj) is NotImplemented


Code review comments:
diff_hunk: @@ -1059,6 +1059,7 @@ static PyObject *
 gentype_richcompare(PyObject *self, PyObject *other, int cmp_op)
 {
     PyObject *arr, *ret;
+    double self_prio, other_prio;
path: numpy/core/src/multiarray/scalartypes.c.src
text: @user1:
```suggestion
```
Soryr, maybe should have marked this too for removal.