datetime cheatsheet. Avoid naive datetimes in 2026.

Construct (aware = with timezone)

from datetime import datetime, date, time, timedelta, timezone
from zoneinfo import ZoneInfo

# Current
datetime.now(timezone.utc)                    # UTC, aware
datetime.now(ZoneInfo("America/New_York"))    # zoned, aware

# WRONG: naive (no timezone)
datetime.now()                                # avoid
datetime.utcnow()                             # deprecated 3.12+

# Construct with tz
dt = datetime(2026, 5, 17, 12, 0, tzinfo=ZoneInfo("UTC"))

ISO 8601 (preferred string format)

# Parse
dt = datetime.fromisoformat("2026-05-17T12:00:00+00:00")

# Format
dt.isoformat()                # "2026-05-17T12:00:00+00:00"

Always use ISO 8601 for transport.

Convert timezones

ny = datetime.now(ZoneInfo("America/New_York"))
in_utc = ny.astimezone(timezone.utc)
in_tokyo = ny.astimezone(ZoneInfo("Asia/Tokyo"))

astimezone converts; doesn’t change the instant.

strptime / strftime

# Parse custom format
dt = datetime.strptime("2026-05-17 12:00:00", "%Y-%m-%d %H:%M:%S")
# Naive! Add tz:
dt = dt.replace(tzinfo=timezone.utc)

# Format
dt.strftime("%Y-%m-%d %H:%M:%S %Z")

Common formats:

%Y    year (2026)
%m    month (01-12)
%d    day (01-31)
%H    hour (00-23)
%M    minute
%S    second
%f    microseconds
%Z    tz name
%z    tz offset (+0000)
%A    weekday full (Saturday)
%a    weekday abbr (Sat)
%B    month full
%b    month abbr
%j    day of year
%U    week of year

Arithmetic

now = datetime.now(timezone.utc)
yesterday = now - timedelta(days=1)
next_week = now + timedelta(weeks=1)
in_2_hours = now + timedelta(hours=2)

# Difference
delta = future - past
delta.total_seconds()
delta.days

Comparing datetimes

a = datetime.now(timezone.utc)
b = datetime.now(timezone.utc)
a < b                          # works (both aware)

Can’t compare naive and aware datetimes — TypeError.

Convert to / from Unix timestamp

ts = dt.timestamp()           # float seconds since epoch
dt = datetime.fromtimestamp(ts, tz=timezone.utc)

Date (no time component)

today = date.today()
date(2026, 5, 17)

Date is timezone-less.

Time (no date)

t = time(12, 30, 0)

Combine date + time + tz

dt = datetime.combine(date.today(), time(12, 0), tzinfo=ZoneInfo("UTC"))

Round to start of day

def start_of_day(dt):
    return dt.replace(hour=0, minute=0, second=0, microsecond=0)

def end_of_day(dt):
    return dt.replace(hour=23, minute=59, second=59, microsecond=999999)

Start / end of month

from calendar import monthrange

def start_of_month(dt):
    return dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)

def end_of_month(dt):
    _, last = monthrange(dt.year, dt.month)
    return dt.replace(day=last, hour=23, minute=59, second=59)

Subtract days respecting calendar

For “1 month ago”: tricky (different month lengths).

from dateutil.relativedelta import relativedelta

dt - relativedelta(months=1)    # 1 month back, smart
dt - relativedelta(years=1)

Requires python-dateutil.

Parse natural language

from dateutil.parser import parse

parse("Aug 28, 2026")           # datetime
parse("2026-05-17T12:00:00Z")

Lenient; useful for user input. For strict: fromisoformat.

Sleep / wait

import time
time.sleep(1)                   # blocks

import asyncio
await asyncio.sleep(1)          # async

Time it

import time

t = time.perf_counter()
do_work()
duration = time.perf_counter() - t

perf_counter for measurements (monotonic; high precision).

Pendulum (alternative)

import pendulum

now = pendulum.now("UTC")
now.add(days=1)
now.subtract(months=1)
now.diff(other).in_hours()

Cleaner API; superset of datetime. Use if you prefer.

Common mistakes

  • Naive datetime — DST, ambiguous, dangerous.
  • datetime.utcnow() — deprecated in 3.12+; use datetime.now(timezone.utc).
  • Storing local times in DB — always UTC.
  • Forgetting DST when adding hours — use relativedelta for human meaning.
  • Sorting mixed naive + aware — TypeError.

Read this next

If you want my datetime utilities library (parse, format, ranges), it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .