Skip to content
>GLB_
Go back

Python datetimes: naive vs aware, date parts, next day and total_seconds

· Updated

Three datetime problems come up again and again in data scripts: comparisons that fail because one value has a timezone and the other doesn’t, turning YYYYMMDD integers into folder paths or the next date, and measuring the gap between two timestamps in seconds. All of them are solved with the standard datetime module.

Fix “can’t compare offset-naive and offset-aware datetimes”

TypeError: can't compare offset-naive and offset-aware datetimes

This error appears when one datetime carries timezone information (offset-aware) and the other doesn’t (offset-naive). Make both the same kind before comparing.

Make a naive datetime aware (UTC)

With replace:

from datetime import datetime, timezone

# Create a naive datetime
cutoff_date = datetime(2024, 10, 17)

# Make it UTC offset-aware
cutoff_date_utc = cutoff_date.replace(tzinfo=timezone.utc)

print(cutoff_date_utc)  # Output: 2024-10-17 00:00:00+00:00

Only do this if you know the naive value already represents UTC. replace attaches a timezone; it doesn’t convert the time.

With pytz, which is useful when you work with several timezones or with libraries that expect pytz objects:

from datetime import datetime
import pytz

# Create a naive datetime
cutoff_date = datetime(2024, 10, 17)

# Make it UTC offset-aware using pytz
utc_timezone = pytz.UTC
cutoff_date_utc = utc_timezone.localize(cutoff_date)

print(cutoff_date_utc)  # Output: 2024-10-17 00:00:00+00:00

Make an aware datetime naive

# Remove timezone information to make it naive
cutoff_date_naive = cutoff_date_utc.replace(tzinfo=None)

print(cutoff_date_naive)  # Output: 2024-10-17 00:00:00

Compare safely

Decide whether your code works with aware or naive datetimes, and convert everything to that kind before comparing:

from datetime import datetime, timezone

# Offset-aware datetime
current_time = datetime.now(timezone.utc)

# Offset-naive datetime
cutoff_date = datetime(2024, 10, 17)

# Convert cutoff_date to offset-aware
cutoff_date_utc = cutoff_date.replace(tzinfo=timezone.utc)

if current_time > cutoff_date_utc:
    print("The current time is past the cutoff date.")
else:
    print("The cutoff date is in the future.")

Timestamps from AWS APIs (S3 LastModified, for example) come back timezone-aware in UTC, which is a common source of this error when a script compares them with datetime(2024, 10, 17).

Extract year, month and day from YYYYMMDD

A typical case is building year/month/day folder paths from an integer date:

from datetime import datetime

def extract_year_month_day(date):
    date_obj = datetime.strptime(str(date), "%Y%m%d")
    year = str(date_obj.year)
    month = str(date_obj.month).zfill(2)  # Ensure leading zero for single-digit months
    day = str(date_obj.day).zfill(2)    # Ensure leading zero for single-digit days
    return year, month, day

today = 20230906
year_folder, month_folder, day_folder = extract_year_month_day(today)

print(f"Year: {year_folder}, Month: {month_folder}, Day: {day_folder}")
Year: 2023, Month: 09, Day: 06

Calculate the next day

from datetime import datetime, timedelta

def next_day(date):
    date_obj = datetime.strptime(str(date), "%Y%m%d")
    next_date = date_obj + timedelta(days=1)
    return next_date.strftime("%Y%m%d")

next_day_date = next_day(today)

print(f"Next day: {next_day_date}")
Next day: 20230907

timedelta(days=1) handles month and year boundaries (20231231 becomes 20240101), and strftime("%Y%m%d") formats the result back to YYYYMMDD.

Seconds between two datetimes: total_seconds(), not .seconds

Subtracting two datetimes gives a timedelta. Its .seconds attribute is tempting but wrong for this: it is only the seconds part of the duration (0 to 86399), with the days stored separately in .days. To get the whole duration in seconds, use total_seconds(), which the Python docs describe as “the total number of seconds contained in the duration”:

from datetime import datetime

start = datetime(2024, 10, 17, 8, 0, 0)
end = datetime(2024, 10, 18, 8, 0, 30)
delta = end - start

print(delta)                  # 1 day, 0:00:30
print(delta.seconds)          # 30
print(delta.total_seconds())  # 86430.0

The same question with more examples: How do I check the difference, in seconds, between two dates?

Gotchas


Share this post:

Related Posts


Previous Post
Extracting the last part of a string after a delimiter in SQL Server
Next Post
Python logging: levels, file output, and separate console and file handlers