Code review example: datetime.now() is naive: comparing it to an aware datetime raises, and it's local time anyway in Python
Retired from the DiffDojo practice pool in October 2026; the review below is the canonical answer. An AI wrote this pull request for the task underneath. Read the diff and decide what you would say before you scroll to the review.
The task
Check whether a token has expired
- is_expired(token) returns True when the token's expiry has passed.
token.expires_atis a timezone-aware UTC datetime (from the database).- The comparison must be correct regardless of the server's local timezone.
Adds the expiry check: compares the token's expiry against the current time and returns whether it has passed. Straightforward datetime comparison.
Servers run in various regions; the DB stores expires_at as timezone-aware UTC.
The diff
app/auth/expiry.py+5The review
Issue 1: datetime.now() is naive: comparing it to an aware datetime raises, and it's local time anyway
datetime.now()is naive and local. It carries no timezone and reflects the server's wall clock.token.expires_atis timezone-aware UTC.- Comparing the two raises. Python refuses to order a naive and an aware datetime:
TypeError: can't compare offset-naive and offset-aware datetimes. The endpoint 500s the moment it checks a token. - The naive path would be a trap too. If
expires_atwere stored naive-but-meaning-UTC (a common mistake), comparing it against localdatetime.now()would be silently wrong by the server's UTC offset, Tokyo and New York would disagree by hours. Naive datetimes are only safe when every value in the comparison is consistently the same zone; mixing a UTC-meaning value with a local-meaningnow()is the danger.
The fix: datetime.now(timezone.utc), an aware UTC value that compares correctly against the aware expires_at everywhere.
The fix
from datetime import datetime, timezone
def is_expired(token) -> bool:
return token.expires_at < datetime.now(timezone.utc)Why it matters
datetime.now() / utcnow() with no tzinfo → you have a naive datetime. The moment it meets an aware one, Python raises; and even alone, now() is local time masquerading as truth. Use datetime.now(timezone.utc).
Real-world stakes: every token check 500s in production the first time it runs against a real timezone-aware expiry, or, in the naive-DB variant, tokens expire hours early or late depending on where the server sits. Naive/aware datetime mixing is Python's most shipped date bug, and assistants default to bare datetime.now() because it's the shortest thing that looks like "current time".
The verdict
Request changes. datetime.now() is naive: comparing it to an aware datetime raises, and it's local time anyway
Try a live one
Python PRs you have not seen the answer to.
Leave inline comments and a verdict, then see what you caught. Free, no signup.
Review a Python PR →