DEV Community

Emily Scott
Emily Scott

Posted on

Why Your Python `datetime` Comparison Fails (Naive vs Aware) — And How to Fix It

A tricky Python problem many developers run into is this:

Your datetime comparison looks correct, but Python throws an error or behaves inconsistently.

This shows up in:

  • Django apps
  • Flask APIs
  • Scheduling systems
  • Cron jobs
  • Token expiration logic
  • Logging systems
  • Time-based filters

Let’s fix it step by step.


The Problem

You write something like this:

from datetime import datetime, timezone

now = datetime.now(timezone.utc)
expiry = datetime.now()

if now > expiry:
    print("Expired")
Enter fullscreen mode Exit fullscreen mode

Error

TypeError: can't compare offset-naive and offset-aware datetimes
Enter fullscreen mode Exit fullscreen mode

Why This Happens

Python has two types of datetime objects:

Naive datetime

datetime.now()
Enter fullscreen mode Exit fullscreen mode
  • No timezone info
  • tzinfo = None

Aware datetime

datetime.now(timezone.utc)
Enter fullscreen mode Exit fullscreen mode
  • Has timezone info
  • Safe for comparisons

The Core Issue

You are comparing:

aware datetime vs naive datetime
Enter fullscreen mode Exit fullscreen mode

Python does not allow this comparison.


Step 1: Make Both Datetimes Consistent

Use either:

  • all naive or
  • all aware

Mixing them causes errors.


Step 2: Use Timezone-Aware Datetimes

Recommended solution:

from datetime import datetime, timezone

now = datetime.now(timezone.utc)
expiry = datetime.now(timezone.utc)

if now > expiry:
    print("Expired")
Enter fullscreen mode Exit fullscreen mode

Step 3: Convert Naive to Aware

If you already have a naive datetime:

expiry = datetime.now()
Enter fullscreen mode Exit fullscreen mode

Convert it:

expiry = expiry.replace(tzinfo=timezone.utc)
Enter fullscreen mode Exit fullscreen mode

Real Django Example

Bad:

from datetime import datetime

if datetime.now() > user.last_login:
    print("Old login")
Enter fullscreen mode Exit fullscreen mode

Correct Django Way

from django.utils import timezone

if timezone.now() > user.last_login:
    print("Old login")
Enter fullscreen mode Exit fullscreen mode

Hidden Bug (No Error, Wrong Result)

event_time = datetime.utcnow()
current_time = datetime.now()

print(event_time < current_time)
Enter fullscreen mode Exit fullscreen mode

Step 4: Use UTC Everywhere

Best practice:

datetime.now(timezone.utc)
Enter fullscreen mode Exit fullscreen mode

Convert to local time only for display.


Quick Debug Rule

Ask yourself:

Are both datetimes using the same timezone?


Final Thoughts

Remember:

  • Naive = no timezone
  • Aware = has timezone
  • Never mix them
  • Prefer UTC
  • Use framework helpers

This prevents subtle bugs in production systems.


Your Turn

Have you faced this datetime issue before?

It is one of the most common hidden bugs in Python.

Peace,
Idioms

Top comments (0)