Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

datetimes and dates should never be equal

Tags:

python

from datetime import datetime, date

class MyDate(date):
    pass

print(MyDate(2024, 3, 8) == datetime(2024, 3, 8))
print(date(2024, 3, 8) == datetime(2024, 3, 8))

Expected output:

False
False

Actual output:

True
False

Why does subclassing datetime.date change the __eq__ result?

like image 464
no step on snek Avatar asked May 28 '26 20:05

no step on snek


1 Answers

Looking at the Python source code for datetime.date.__eq__ (the fallback implementation), we find the following definition, which does not implement an equality operator between a datetime.date object and a datetime.datetime object (in that order):

def __eq__(self, other):
    if isinstance(other, date) and not isinstance(other, datetime):
        return self._cmp(other) == 0
    return NotImplemented

In the example where the result is False, the self object are instances of datetime.date, and are not instances of datetime.datetime (satisfying the if condition), so they get compared and __eq__ returns whatever the result of the comparison is.

Similarly, as noted by @Abdul Niyas P M, by looking at the C implementation of this operator (which is the default implementation), the definition is equivalent in logic, and further contains comments on this particular behavior:

static PyObject *
date_richcompare(PyObject *self, PyObject *other, int op)
{
    /* Since DateTime is a subclass of Date, if the other object is
     * a DateTime, it would compute an equality testing or an ordering
     * based on the date part alone, and we don't want that.
     * So return NotImplemented here in that case.
     * If a subclass wants to change this, it's up to the subclass to do so.
     * The behavior is the same as if Date and DateTime were independent
     * classes.
     */
    if (PyDate_Check(other) && !PyDateTime_Check(other)) {
        int diff = memcmp(((PyDateTime_Date *)self)->data,
                          ((PyDateTime_Date *)other)->data,
                          _PyDateTime_DATE_DATASIZE);
        return diff_to_bool(diff, op);
    }
    else
        Py_RETURN_NOTIMPLEMENTED;
}

However, the fact False is being returned instead of NotImplemented raises another question, but this could be due to the Python version the OP was using when running their code.

For instance, the 3.12.2 version source code of the same method (and C implementation) does not prevent the comparison when other is a datetime.datetime:

def __eq__(self, other):
    if isinstance(other, date):
        return self._cmp(other) == 0
    return NotImplemented
like image 88
MrGeek Avatar answered May 30 '26 09:05

MrGeek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!