or datetime objects.
*datetime1* is considered less than *datetime2* when *datetime1* precedes
*datetime2* in time.
- If one comparand is naive and the other is aware, :exc:`TypeError` is raised.
+ If one comparand is naive and the other is aware, :exc:`TypeError`
+ is raised if an order comparison is attempted. For equality
+ comparisons, naive instances are never equal to aware instances.
+
If both comparands are aware, and have the same :attr:`tzinfo` attribute, the
common :attr:`tzinfo` attribute is ignored and the base datetimes are
compared. If both comparands are aware and have different :attr:`tzinfo`
attributes, the comparands are first adjusted by subtracting their UTC
offsets (obtained from ``self.utcoffset()``).
+ .. versionchanged:: 3.3
+
+ Equality comparisons between naive and aware :class:`datetime`
+ instances don't raise :exc:`TypeError`.
+
.. note::
In order to stop comparison from falling back to the default scheme of comparing
* comparison of :class:`.time` to :class:`.time`, where *a* is considered less
than *b* when *a* precedes *b* in time. If one comparand is naive and the other
- is aware, :exc:`TypeError` is raised. If both comparands are aware, and have
+ is aware, :exc:`TypeError` is raised if an order comparison is attempted. For equality
+ comparisons, naive instances are never equal to aware instances.
+
+ If both comparands are aware, and have
the same :attr:`tzinfo` attribute, the common :attr:`tzinfo` attribute is
ignored and the base times are compared. If both comparands are aware and
have different :attr:`tzinfo` attributes, the comparands are first adjusted by
different type, :exc:`TypeError` is raised unless the comparison is ``==`` or
``!=``. The latter cases return :const:`False` or :const:`True`, respectively.
+ .. versionchanged:: 3.3
+
+ Equality comparisons between naive and aware :class:`time` instances
+ don't raise :exc:`TypeError`.
+
* hash, use as dict key
* efficient pickling
def __eq__(self, other):
if isinstance(other, time):
- return self._cmp(other) == 0
+ return self._cmp(other, allow_mixed=True) == 0
else:
return False
def __ne__(self, other):
if isinstance(other, time):
- return self._cmp(other) != 0
+ return self._cmp(other, allow_mixed=True) != 0
else:
return True
else:
_cmperror(self, other)
- def _cmp(self, other):
+ def _cmp(self, other, allow_mixed=False):
assert isinstance(other, time)
mytz = self._tzinfo
ottz = other._tzinfo
(other._hour, other._minute, other._second,
other._microsecond))
if myoff is None or otoff is None:
- raise TypeError("cannot compare naive and aware times")
+ if allow_mixed:
+ return 2 # arbitrary non-zero value
+ else:
+ raise TypeError("cannot compare naive and aware times")
myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
return _cmp((myhhmm, self._second, self._microsecond),
def __eq__(self, other):
if isinstance(other, datetime):
- return self._cmp(other) == 0
+ return self._cmp(other, allow_mixed=True) == 0
elif not isinstance(other, date):
return NotImplemented
else:
def __ne__(self, other):
if isinstance(other, datetime):
- return self._cmp(other) != 0
+ return self._cmp(other, allow_mixed=True) != 0
elif not isinstance(other, date):
return NotImplemented
else:
else:
_cmperror(self, other)
- def _cmp(self, other):
+ def _cmp(self, other, allow_mixed=False):
assert isinstance(other, datetime)
mytz = self._tzinfo
ottz = other._tzinfo
other._hour, other._minute, other._second,
other._microsecond))
if myoff is None or otoff is None:
- raise TypeError("cannot compare naive and aware datetimes")
+ if allow_mixed:
+ return 2 # arbitrary non-zero value
+ else:
+ raise TypeError("cannot compare naive and aware datetimes")
# XXX What follows could be done more efficiently...
diff = self - other # this will take offsets into account
if diff.days < 0:
self.assertEqual(t1, t2)
self.assertEqual(t1, t3)
self.assertEqual(t2, t3)
- self.assertRaises(TypeError, lambda: t4 == t5) # mixed tz-aware & naive
+ self.assertNotEqual(t4, t5) # mixed tz-aware & naive
self.assertRaises(TypeError, lambda: t4 < t5) # mixed tz-aware & naive
self.assertRaises(TypeError, lambda: t5 < t4) # mixed tz-aware & naive
t2 = t2.replace(tzinfo=FixedOffset(None, ""))
self.assertEqual(t1, t2)
t2 = t2.replace(tzinfo=FixedOffset(0, ""))
- self.assertRaises(TypeError, lambda: t1 == t2)
+ self.assertNotEqual(t1, t2)
# In time w/ identical tzinfo objects, utcoffset is ignored.
class Varies(tzinfo):
microsecond=1)
self.assertTrue(t1 > t2)
- # Make t2 naive and it should fail.
+ # Make t2 naive and it should differ.
t2 = self.theclass.min
- self.assertRaises(TypeError, lambda: t1 == t2)
+ self.assertNotEqual(t1, t2)
self.assertEqual(t2, t2)
# It's also naive if it has tzinfo but tzinfo.utcoffset() is None.
class Naive(tzinfo):
def utcoffset(self, dt): return None
t2 = self.theclass(5, 6, 7, tzinfo=Naive())
- self.assertRaises(TypeError, lambda: t1 == t2)
+ self.assertNotEqual(t1, t2)
self.assertEqual(t2, t2)
# OTOH, it's OK to compare two of these mixing the two ways of being
t2 = t2.replace(tzinfo=FixedOffset(None, ""))
self.assertEqual(t1, t2)
t2 = t2.replace(tzinfo=FixedOffset(0, ""))
- self.assertRaises(TypeError, lambda: t1 == t2)
+ self.assertNotEqual(t1, t2)
# In datetime w/ identical tzinfo objects, utcoffset is ignored.
class Varies(tzinfo):
Library
-------
-- Issue #14938: importlib.abc.SourceLoader.is_package() will not consider a
- module whose name ends in '__init__' a package (e.g. importing pkg.__init__
- directly should be considered a module, not a package).
+- Issue #15006: Allow equality comparison between naive and aware
+ time or datetime objects.
- Issue #14982: Document that pkgutil's iteration functions require the
non-standard iter_modules() method to be defined by an importer (something
TIME_GET_MICROSECOND(other);
result = diff_to_bool(diff, op);
}
+ else if (op == Py_EQ) {
+ result = Py_False;
+ Py_INCREF(result);
+ }
+ else if (op == Py_NE) {
+ result = Py_True;
+ Py_INCREF(result);
+ }
else {
PyErr_SetString(PyExc_TypeError,
"can't compare offset-naive and "
Py_DECREF(delta);
result = diff_to_bool(diff, op);
}
+ else if (op == Py_EQ) {
+ result = Py_False;
+ Py_INCREF(result);
+ }
+ else if (op == Py_NE) {
+ result = Py_True;
+ Py_INCREF(result);
+ }
else {
PyErr_SetString(PyExc_TypeError,
"can't compare offset-naive and "