<p dir="auto">Should the functions <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram2d.html" rel="nofollow"><code class="notranslate">histogram2d</code></a> and <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.histogramdd.html" rel="nofollow"><code class="notranslate">histogramdd</code></a> have the keyword <code class="notranslate">density</code> added and <code class="notranslate">normed</code> deprecated, to match <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram.html" rel="nofollow"><code class="notranslate">histogram</code></a>?</p>
<p dir="auto">Sort order for <code class="notranslate">NaT</code> values got <a href="https://numpy.org/doc/stable/release/1.18.0-notes.html#nat-now-sorts-to-the-end-of-arrays" rel="nofollow">changed in numpy 1.18.0</a>.</p>
<p dir="auto"><code class="notranslate">PyArray_CompareFunc</code> of dtype <code class="notranslate">datetime64</code> returns incorrect as per the updated sort order.</p>
<p dir="auto">This is present with numpy 1.20.2 and 1.21 too.</p>
<p dir="auto">This is reproducible via the following extension module.</p>
<p dir="auto">compare_bug.c</p>
<div class="highlight highlight-source-c notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#include &lt;Python.h&gt;
#include &quot;numpy/arrayobject.h&quot;
#include &quot;numpy/ndarrayobject.h&quot;
#include &quot;numpy/ndarraytypes.h&quot;
#include &quot;numpy/arrayscalars.h&quot;
#include &quot;numpy/ufuncobject.h&quot;


static PyObject*
reproduce_bug(PyObject* self, PyObject* args) {
    PyObject *arr = NULL;
    if (!PyArg_ParseTuple(args, &quot;|O&quot;, &amp;arr)) {
        return Py_None;
    }
    PyArrayObject *numpy_arr = (PyArrayObject*) arr;
    // We just compare 0th and 1st element and print out
    // the returned value.
    int x = numpy_arr-&gt;descr-&gt;f-&gt;compare(
        PyArray_GETPTR1(numpy_arr, 0),
        PyArray_GETPTR1(numpy_arr, 1),
        numpy_arr
    );
    printf(&quot;DEBUG %d\n&quot;, x);
    return Py_None;
}

static PyMethodDef bug_functions[] = {
    {&quot;bug&quot;, (PyCFunction)reproduce_bug, METH_VARARGS, NULL},
    { NULL, NULL, 0, NULL }
};

static struct PyModuleDef numpybugmodule = {
    PyModuleDef_HEAD_INIT,
    &quot;numpy_bug&quot;,
    NULL,
    -1,   
    bug_functions
};

PyMODINIT_FUNC
PyInit_numpy_bug(void)
{
    return PyModule_Create(&amp;numpybugmodule);
}"><pre class="notranslate"><span class="pl-k">#include</span> <span class="pl-s">&lt;Python.h&gt;</span>
<span class="pl-k">#include</span> <span class="pl-s">"numpy/arrayobject.h"</span>
<span class="pl-k">#include</span> <span class="pl-s">"numpy/ndarrayobject.h"</span>
<span class="pl-k">#include</span> <span class="pl-s">"numpy/ndarraytypes.h"</span>
<span class="pl-k">#include</span> <span class="pl-s">"numpy/arrayscalars.h"</span>
<span class="pl-k">#include</span> <span class="pl-s">"numpy/ufuncobject.h"</span>


<span class="pl-k">static</span> <span class="pl-smi">PyObject</span><span class="pl-c1">*</span>
<span class="pl-en">reproduce_bug</span>(<span class="pl-smi">PyObject</span><span class="pl-c1">*</span> <span class="pl-s1">self</span>, <span class="pl-smi">PyObject</span><span class="pl-c1">*</span> <span class="pl-s1">args</span>) {
    <span class="pl-smi">PyObject</span> <span class="pl-c1">*</span><span class="pl-s1">arr</span> <span class="pl-c1">=</span> <span class="pl-c1">NULL</span>;
    <span class="pl-k">if</span> (!<span class="pl-en">PyArg_ParseTuple</span>(<span class="pl-s1">args</span>, <span class="pl-s">"|O"</span>, <span class="pl-c1">&amp;</span><span class="pl-s1">arr</span>)) {
        <span class="pl-k">return</span> <span class="pl-s1">Py_None</span>;
    }
    <span class="pl-smi">PyArrayObject</span> <span class="pl-c1">*</span><span class="pl-s1">numpy_arr</span> <span class="pl-c1">=</span> (<span class="pl-smi">PyArrayObject</span><span class="pl-c1">*</span>) <span class="pl-s1">arr</span>;
    <span class="pl-c">// We just compare 0th and 1st element and print out</span>
    <span class="pl-c">// the returned value.</span>
    <span class="pl-smi">int</span> <span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">numpy_arr</span><span class="pl-c1">-&gt;</span><span class="pl-c1">descr</span><span class="pl-c1">-&gt;</span><span class="pl-c1">f</span><span class="pl-c1">-&gt;</span><span class="pl-en">compare</span>(
        <span class="pl-en">PyArray_GETPTR1</span>(<span class="pl-s1">numpy_arr</span>, <span class="pl-c1">0</span>),
        <span class="pl-en">PyArray_GETPTR1</span>(<span class="pl-s1">numpy_arr</span>, <span class="pl-c1">1</span>),
        <span class="pl-s1">numpy_arr</span>
    );
    <span class="pl-en">printf</span>(<span class="pl-s">"DEBUG %d\n"</span>, <span class="pl-s1">x</span>);
    <span class="pl-k">return</span> <span class="pl-s1">Py_None</span>;
}

<span class="pl-k">static</span> <span class="pl-smi">PyMethodDef</span> <span class="pl-s1">bug_functions</span>[] <span class="pl-c1">=</span> {
    {<span class="pl-s">"bug"</span>, (<span class="pl-smi">PyCFunction</span>)<span class="pl-s1">reproduce_bug</span>, <span class="pl-c1">METH_VARARGS</span>, <span class="pl-c1">NULL</span>},
    { <span class="pl-c1">NULL</span>, <span class="pl-c1">NULL</span>, <span class="pl-c1">0</span>, <span class="pl-c1">NULL</span> }
};

<span class="pl-k">static</span> <span class="pl-k">struct</span> <span class="pl-smi">PyModuleDef</span> <span class="pl-s1">numpybugmodule</span> <span class="pl-c1">=</span> {
    <span class="pl-s1">PyModuleDef_HEAD_INIT</span>,
    <span class="pl-s">"numpy_bug"</span>,
    <span class="pl-c1">NULL</span>,
    <span class="pl-c1">-1</span>,   
    <span class="pl-s1">bug_functions</span>
};

<span class="pl-smi">PyMODINIT_FUNC</span>
<span class="pl-en">PyInit_numpy_bug</span>(<span class="pl-smi">void</span>)
{
    <span class="pl-k">return</span> <span class="pl-en">PyModule_Create</span>(<span class="pl-c1">&amp;</span><span class="pl-s1">numpybugmodule</span>);
}</pre></div>
<p dir="auto">setup.py</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from distutils.core import setup, Extension, DEBUG
import numpy

extra_compile_args = [&quot;-DNDEBUG&quot;, &quot;-O3&quot;]
sfc_module = Extension('numpy_bug', sources = ['compare_bug..c'],
                        include_dirs=[numpy.get_include()],
                       extra_compile_args=extra_compile_args)

setup(name = 'mtnumpy', version = '1.0',
    description = 'Python Package with superfastcode C++ extension',
    ext_modules = [sfc_module]
    )"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">distutils</span>.<span class="pl-s1">core</span> <span class="pl-k">import</span> <span class="pl-s1">setup</span>, <span class="pl-v">Extension</span>, <span class="pl-v">DEBUG</span>
<span class="pl-k">import</span> <span class="pl-s1">numpy</span>

<span class="pl-s1">extra_compile_args</span> <span class="pl-c1">=</span> [<span class="pl-s">"-DNDEBUG"</span>, <span class="pl-s">"-O3"</span>]
<span class="pl-s1">sfc_module</span> <span class="pl-c1">=</span> <span class="pl-v">Extension</span>(<span class="pl-s">'numpy_bug'</span>, <span class="pl-s1">sources</span> <span class="pl-c1">=</span> [<span class="pl-s">'compare_bug..c'</span>],
                        <span class="pl-s1">include_dirs</span><span class="pl-c1">=</span>[<span class="pl-s1">numpy</span>.<span class="pl-en">get_include</span>()],
                       <span class="pl-s1">extra_compile_args</span><span class="pl-c1">=</span><span class="pl-s1">extra_compile_args</span>)

<span class="pl-en">setup</span>(<span class="pl-s1">name</span> <span class="pl-c1">=</span> <span class="pl-s">'mtnumpy'</span>, <span class="pl-s1">version</span> <span class="pl-c1">=</span> <span class="pl-s">'1.0'</span>,
    <span class="pl-s1">description</span> <span class="pl-c1">=</span> <span class="pl-s">'Python Package with superfastcode C++ extension'</span>,
    <span class="pl-s1">ext_modules</span> <span class="pl-c1">=</span> [<span class="pl-s1">sfc_module</span>]
    )</pre></div>
<p dir="auto">Running this after installing above:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In [1]: import numpy, numpy_bug

In [2]: numpy_bug.bug(numpy.array(['NaT', '2020-01-01'], dtype='datetime64[s]')) # should print 1 as per new sort order.
DEBUG -1"><pre class="notranslate"><span class="pl-v">In</span> [<span class="pl-c1">1</span>]: <span class="pl-s1">import</span> <span class="pl-s1">numpy</span>, <span class="pl-s1">numpy_bug</span>

<span class="pl-v">In</span> [<span class="pl-c1">2</span>]: <span class="pl-s1">numpy_bug</span>.<span class="pl-en">bug</span>(<span class="pl-s1">numpy</span>.<span class="pl-en">array</span>([<span class="pl-s">'NaT'</span>, <span class="pl-s">'2020-01-01'</span>], <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">'datetime64[s]'</span>)) <span class="pl-c"># should print 1 as per new sort order.</span>
<span class="pl-v">DEBUG</span> <span class="pl-c1">-</span><span class="pl-c1">1</span></pre></div>