Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 528ca53

Browse files
committed
SF bug #1028306: date-datetime comparison
Treat comparing a date to a datetime like a mixed-type comparison.
1 parent c74298a commit 528ca53

3 files changed

Lines changed: 64 additions & 1 deletion

File tree

Lib/test/test_datetime.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3151,6 +3151,48 @@ def fromutc(self, dt):
31513151
fstart += HOUR
31523152

31533153

3154+
#############################################################################
3155+
# oddballs
3156+
3157+
class Oddballs(unittest.TestCase):
3158+
3159+
def test_bug_1028306(self):
3160+
# Trying to compare a date to a datetime should act like a mixed-
3161+
# type comparison, despite that datetime is a subclass of date.
3162+
as_date = date.today()
3163+
as_datetime = datetime.combine(as_date, time())
3164+
self.assert_(as_date != as_datetime)
3165+
self.assert_(as_datetime != as_date)
3166+
self.assert_(not as_date == as_datetime)
3167+
self.assert_(not as_datetime == as_date)
3168+
self.assertRaises(TypeError, lambda: as_date < as_datetime)
3169+
self.assertRaises(TypeError, lambda: as_datetime < as_date)
3170+
self.assertRaises(TypeError, lambda: as_date <= as_datetime)
3171+
self.assertRaises(TypeError, lambda: as_datetime <= as_date)
3172+
self.assertRaises(TypeError, lambda: as_date > as_datetime)
3173+
self.assertRaises(TypeError, lambda: as_datetime > as_date)
3174+
self.assertRaises(TypeError, lambda: as_date >= as_datetime)
3175+
self.assertRaises(TypeError, lambda: as_datetime >= as_date)
3176+
3177+
# Neverthelss, comparison should work with the base-class (date)
3178+
# projection if use of a date method is forced.
3179+
self.assert_(as_date.__eq__(as_datetime))
3180+
different_day = (as_date.day + 1) % 20 + 1
3181+
self.assert_(not as_date.__eq__(as_datetime.replace(day=
3182+
different_day)))
3183+
3184+
# And date should compare with other subclasses of date. If a
3185+
# subclass wants to stop this, it's up to the subclass to do so.
3186+
date_sc = SubclassDate(as_date.year, as_date.month, as_date.day)
3187+
self.assertEqual(as_date, date_sc)
3188+
self.assertEqual(date_sc, as_date)
3189+
3190+
# Ditto for datetimes.
3191+
datetime_sc = SubclassDatetime(as_datetime.year, as_datetime.month,
3192+
as_date.day, 0, 0, 0)
3193+
self.assertEqual(as_datetime, datetime_sc)
3194+
self.assertEqual(datetime_sc, as_datetime)
3195+
31543196
def test_suite():
31553197
allsuites = [unittest.makeSuite(klass, 'test')
31563198
for klass in (TestModule,
@@ -3163,6 +3205,7 @@ def test_suite():
31633205
TestTimeTZ,
31643206
TestDateTimeTZ,
31653207
TestTimezoneConversions,
3208+
Oddballs,
31663209
)
31673210
]
31683211
return unittest.TestSuite(allsuites)

Misc/NEWS

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ Extension modules
2222
Library
2323
-------
2424

25+
- SF bug #1028306: Trying to compare a ``datetime.date`` to a
26+
``datetime.datetime`` mistakenly compared only the year, month and day.
27+
Now it acts like a mixed-type comparison: ``False`` for ``==``,
28+
``True`` for ``!=``, and raises ``TypeError`` for other comparison
29+
operators. Because datetime is a subclass of date, comparing only the
30+
base class (date) members can still be done, if that's desired, by
31+
forcing using of the approprate date method; e.g.,
32+
``a_date.__eq__(a_datetime)`` is true if and only if the year, month
33+
and day members of ``a_date`` and ``a_datetime`` are equal.
34+
2535
- bdist_rpm now supports command line options --force-arch,
2636
{pre,post}-install, {pre,post}-uninstall, and
2737
{prep,build,install,clean,verify}-script.

Modules/datetimemodule.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4075,7 +4075,17 @@ datetime_richcompare(PyDateTime_DateTime *self, PyObject *other, int op)
40754075
int offset1, offset2;
40764076

40774077
if (! PyDateTime_Check(other)) {
4078-
if (PyObject_HasAttrString(other, "timetuple")) {
4078+
/* If other has a "timetuple" attr, that's an advertised
4079+
* hook for other classes to ask to get comparison control.
4080+
* However, date instances have a timetuple attr, and we
4081+
* don't want to allow that comparison. Because datetime
4082+
* is a subclass of date, when mixing date and datetime
4083+
* in a comparison, Python gives datetime the first shot
4084+
* (it's the more specific subtype). So we can stop that
4085+
* combination here reliably.
4086+
*/
4087+
if (PyObject_HasAttrString(other, "timetuple") &&
4088+
! PyDate_Check(other)) {
40794089
/* A hook for other kinds of datetime objects. */
40804090
Py_INCREF(Py_NotImplemented);
40814091
return Py_NotImplemented;

0 commit comments

Comments
 (0)