Comparison and equality¶
All types support equality and comparison.
However, PlainDateTime instances are
never equal or comparable to the “exact” types.
Exact time¶
For exact types (Instant, OffsetDateTime,
ZonedDateTime),
comparison and equality are based on whether they represent the same moment in
time. This means that two objects with different values can be equal:
>>> # different ways of representing the same moment in time
>>> inst = Instant.from_utc(2023, 12, 28, 11, 30)
>>> as_5hr_offset = OffsetDateTime(2023, 12, 28, 16, 30, offset=5)
>>> as_8hr_offset = OffsetDateTime(2023, 12, 28, 19, 30, offset=8)
>>> in_nyc = ZonedDateTime(2023, 12, 28, 6, 30, tz="America/New_York")
>>> # all equal
>>> inst == as_5hr_offset == as_8hr_offset == in_nyc
True
>>> # comparison
>>> in_nyc > OffsetDateTime(2023, 12, 28, 11, 30, offset=5)
True
Note that if you want to compare for exact equality on the values
(i.e. exactly the same year, month, day, hour, minute, etc.), you can use
the exact_eq() method.
>>> d = OffsetDateTime(2023, 12, 28, 11, 30, offset=5)
>>> same = OffsetDateTime(2023, 12, 28, 11, 30, offset=5)
>>> same_moment = OffsetDateTime(2023, 12, 28, 12, 30, offset=6)
>>> d == same_moment
True
>>> d.exact_eq(same_moment)
False
>>> d.exact_eq(same)
True
Local time¶
For PlainDateTime, equality is simply based on
whether the values are the same, since there is no concept of timezones or UTC offset:
>>> d = PlainDateTime(2023, 12, 28, 11, 30)
>>> same = PlainDateTime(2023, 12, 28, 11, 30)
>>> different = PlainDateTime(2023, 12, 28, 11, 31)
>>> d == same
True
>>> d == different
False
See also
See the documentation of __eq__ (exact)
and PlainDateTime.__eq__ for more details.
Strict equality¶
Local and exact types are never equal or comparable to each other.
However, to comply with the Python data model, the equality operator
won’t prevent you from using == to compare them.
To prevent these mix-ups, use mypy’s --strict-equality flag.
>>> # These are never equal, but Python won't stop you from comparing them.
>>> # Mypy will catch this mix-up if you use enable --strict-equality flag.
>>> Instant.from_utc(2023, 12, 28) == PlainDateTime(2023, 12, 28)
False
Why not raise a TypeError?
It may seem like the equality operator should raise a TypeError
in these cases, but this would result in
surprising behavior
when using values as dictionary keys.
Unfortunately, mypy’s --strict-equality is very strict,
forcing you to match exact types exactly.
x = Instant.from_utc(2023, 12, 28, 10)
# mypy: ✅
x == Instant.from_utc(2023, 12, 28, 10)
# mypy: ❌ (too strict, this should be allowed)
x == OffsetDateTime(2023, 12, 28, 11, offset=1)
To work around this, you can either convert explicitly:
x == OffsetDateTime(2023, 12, 28, 11, offset=1).to_instant()
Or annotate with a union:
x: OffsetDateTime | Instant == OffsetDateTime(2023, 12, 28, 11, offset=1)