summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2004-09-16 01:30:50 (GMT)
committerTim Peters <tim.peters@gmail.com>2004-09-16 01:30:50 (GMT)
commit528ca53b7455b3307cb0e3f097ae951191521ba8 (patch)
treebad5eb084b5b64040699077cae94427ae750672f
parentc74298a72b16d2ecca144df014014796f025ea08 (diff)
downloadcpython-528ca53b7455b3307cb0e3f097ae951191521ba8.zip
cpython-528ca53b7455b3307cb0e3f097ae951191521ba8.tar.gz
cpython-528ca53b7455b3307cb0e3f097ae951191521ba8.tar.bz2
SF bug #1028306: date-datetime comparison
Treat comparing a date to a datetime like a mixed-type comparison.
-rw-r--r--Lib/test/test_datetime.py43
-rw-r--r--Misc/NEWS10
-rw-r--r--Modules/datetimemodule.c12
3 files changed, 64 insertions, 1 deletions
diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py
index 2a6aca2..ab7bd71 100644
--- a/Lib/test/test_datetime.py
+++ b/Lib/test/test_datetime.py
@@ -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)
diff --git a/Misc/NEWS b/Misc/NEWS
index 1ade365..fcc52d7 100644
--- a/Misc/NEWS
+++ b/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.
diff --git a/Modules/datetimemodule.c b/Modules/datetimemodule.c
index ee7387c..6312e21 100644
--- a/Modules/datetimemodule.c
+++ b/Modules/datetimemodule.c
@@ -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;