SF bug #1028306: date-datetime comparison
Treat comparing a date to a datetime like a mixed-type comparison.
This commit is contained in:
parent
c74298a72b
commit
528ca53b74
|
@ -3151,6 +3151,48 @@ class TestTimezoneConversions(unittest.TestCase):
|
|||
fstart += HOUR
|
||||
|
||||
|
||||
#############################################################################
|
||||
# oddballs
|
||||
|
||||
class Oddballs(unittest.TestCase):
|
||||
|
||||
def test_bug_1028306(self):
|
||||
# Trying to compare a date to a datetime should act like a mixed-
|
||||
# type comparison, despite that datetime is a subclass of date.
|
||||
as_date = date.today()
|
||||
as_datetime = datetime.combine(as_date, time())
|
||||
self.assert_(as_date != as_datetime)
|
||||
self.assert_(as_datetime != as_date)
|
||||
self.assert_(not as_date == as_datetime)
|
||||
self.assert_(not as_datetime == as_date)
|
||||
self.assertRaises(TypeError, lambda: as_date < as_datetime)
|
||||
self.assertRaises(TypeError, lambda: as_datetime < as_date)
|
||||
self.assertRaises(TypeError, lambda: as_date <= as_datetime)
|
||||
self.assertRaises(TypeError, lambda: as_datetime <= as_date)
|
||||
self.assertRaises(TypeError, lambda: as_date > as_datetime)
|
||||
self.assertRaises(TypeError, lambda: as_datetime > as_date)
|
||||
self.assertRaises(TypeError, lambda: as_date >= as_datetime)
|
||||
self.assertRaises(TypeError, lambda: as_datetime >= as_date)
|
||||
|
||||
# Neverthelss, comparison should work with the base-class (date)
|
||||
# projection if use of a date method is forced.
|
||||
self.assert_(as_date.__eq__(as_datetime))
|
||||
different_day = (as_date.day + 1) % 20 + 1
|
||||
self.assert_(not as_date.__eq__(as_datetime.replace(day=
|
||||
different_day)))
|
||||
|
||||
# And date should compare with other subclasses of date. If a
|
||||
# subclass wants to stop this, it's up to the subclass to do so.
|
||||
date_sc = SubclassDate(as_date.year, as_date.month, as_date.day)
|
||||
self.assertEqual(as_date, date_sc)
|
||||
self.assertEqual(date_sc, as_date)
|
||||
|
||||
# Ditto for datetimes.
|
||||
datetime_sc = SubclassDatetime(as_datetime.year, as_datetime.month,
|
||||
as_date.day, 0, 0, 0)
|
||||
self.assertEqual(as_datetime, datetime_sc)
|
||||
self.assertEqual(datetime_sc, as_datetime)
|
||||
|
||||
def test_suite():
|
||||
allsuites = [unittest.makeSuite(klass, 'test')
|
||||
for klass in (TestModule,
|
||||
|
@ -3163,6 +3205,7 @@ def test_suite():
|
|||
TestTimeTZ,
|
||||
TestDateTimeTZ,
|
||||
TestTimezoneConversions,
|
||||
Oddballs,
|
||||
)
|
||||
]
|
||||
return unittest.TestSuite(allsuites)
|
||||
|
|
10
Misc/NEWS
10
Misc/NEWS
|
@ -22,6 +22,16 @@ Extension modules
|
|||
Library
|
||||
-------
|
||||
|
||||
- SF bug #1028306: Trying to compare a ``datetime.date`` to a
|
||||
``datetime.datetime`` mistakenly compared only the year, month and day.
|
||||
Now it acts like a mixed-type comparison: ``False`` for ``==``,
|
||||
``True`` for ``!=``, and raises ``TypeError`` for other comparison
|
||||
operators. Because datetime is a subclass of date, comparing only the
|
||||
base class (date) members can still be done, if that's desired, by
|
||||
forcing using of the approprate date method; e.g.,
|
||||
``a_date.__eq__(a_datetime)`` is true if and only if the year, month
|
||||
and day members of ``a_date`` and ``a_datetime`` are equal.
|
||||
|
||||
- bdist_rpm now supports command line options --force-arch,
|
||||
{pre,post}-install, {pre,post}-uninstall, and
|
||||
{prep,build,install,clean,verify}-script.
|
||||
|
|
|
@ -4075,7 +4075,17 @@ datetime_richcompare(PyDateTime_DateTime *self, PyObject *other, int op)
|
|||
int offset1, offset2;
|
||||
|
||||
if (! PyDateTime_Check(other)) {
|
||||
if (PyObject_HasAttrString(other, "timetuple")) {
|
||||
/* If other has a "timetuple" attr, that's an advertised
|
||||
* hook for other classes to ask to get comparison control.
|
||||
* However, date instances have a timetuple attr, and we
|
||||
* don't want to allow that comparison. Because datetime
|
||||
* is a subclass of date, when mixing date and datetime
|
||||
* in a comparison, Python gives datetime the first shot
|
||||
* (it's the more specific subtype). So we can stop that
|
||||
* combination here reliably.
|
||||
*/
|
||||
if (PyObject_HasAttrString(other, "timetuple") &&
|
||||
! PyDate_Check(other)) {
|
||||
/* A hook for other kinds of datetime objects. */
|
||||
Py_INCREF(Py_NotImplemented);
|
||||
return Py_NotImplemented;
|
||||
|
|
Loading…
Reference in New Issue