date — calendar date with no time. time — clock time with no date. datetime — both. timedelta — a duration (positive or negative). Most of your code uses datetime and timedelta; the others come up less often.
Naive vs aware — the timezone distinction
A "naive" datetime has no timezone info. An "aware" datetime has a tzinfo attached. Mixing them in arithmetic raises. The 2020s answer: always use aware datetimes. Construct them with datetime.now(timezone.utc) or datetime.fromisoformat with a timezone in the string. The zoneinfo module (3.9+) gives you ZoneInfo("Asia/Seoul") for IANA-named zones.
The ISO 8601 lifeline
datetime.fromisoformat("2026-05-02T15:30:00+09:00") parses, dt.isoformat() emits. Round-trippable, sortable as strings, unambiguous. Modern code defaults to ISO 8601 for serialization. strftime/strptime handle other formats; only reach for them when you must.
timedelta — durations and arithmetic
timedelta(days=7, hours=3) is a duration. Datetimes minus datetimes give a timedelta. Datetimes plus timedelta gives a datetime. Comparisons work. Common idiom: now + timedelta(days=30) for "30 days from now."
Principle: Store and transmit datetimes as ISO 8601 strings with a UTC offset. Convert to local time only at display. Mixing naive and aware datetimes is the most common datetime bug; using aware everywhere makes it impossible.
Code
Construction and formatting·python
from datetime import datetime, date, time, timedelta, timezone
from zoneinfo import ZoneInfo
# Today, now
print(date.today()) # 2026-05-02
print(datetime.now()) # naive — bad! avoid in modern code
print(datetime.now(timezone.utc)) # aware — good
print(datetime.now(ZoneInfo("Asia/Seoul"))) # aware in Seoul time
# Construction
dt = datetime(2026, 5, 2, 15, 30, tzinfo=ZoneInfo("Asia/Seoul"))
print(dt) # 2026-05-02 15:30:00+09:00
# ISO format — the modern standard
print(dt.isoformat()) # 2026-05-02T15:30:00+09:00
print(datetime.fromisoformat("2026-05-02T15:30:00+09:00")) # round-trip
Naive vs aware — and why the distinction matters·python
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
naive = datetime(2026, 5, 2, 15, 30)
aware = datetime(2026, 5, 2, 15, 30, tzinfo=timezone.utc)
# Mixing them in arithmetic raises
try:
aware - naive
except TypeError as e:
print("failed:", e)
# Convert naive to aware (assume it's UTC)
aware_from_naive = naive.replace(tzinfo=timezone.utc)
print(aware - aware_from_naive) # 0 — same instant
# Convert aware to a different zone
seoul = aware.astimezone(ZoneInfo("Asia/Seoul"))
print(seoul) # 2026-05-03 00:30:00+09:00
timedelta — arithmetic on dates·python
from datetime import datetime, timedelta, timezone
now = datetime.now(timezone.utc)
in_a_week = now + timedelta(days=7)
yesterday = now - timedelta(days=1)
print(in_a_week - now) # 7 days, 0:00:00
print(now - yesterday) # 1 day, 0:00:00
# Total seconds
delta = in_a_week - now
print(delta.total_seconds()) # 604800
# Components
print(delta.days) # 7
print(timedelta(hours=25).days) # 1 — hours overflow into days
strftime / strptime — non-ISO formats·python
from datetime import datetime
dt = datetime(2026, 5, 2, 15, 30)
# strftime — datetime to string
print(dt.strftime("%Y-%m-%d")) # 2026-05-02
print(dt.strftime("%B %d, %Y")) # May 02, 2026
print(dt.strftime("%I:%M %p")) # 03:30 PM
# strptime — string to datetime
parsed = datetime.strptime("05/02/2026 15:30", "%m/%d/%Y %H:%M")
print(parsed)
# When you can, prefer fromisoformat. Only use strptime
# for non-ISO formats you can't change.
Common operations — diff in days, day name, weekday·python
from datetime import date, timedelta
birthday = date(2025, 6, 15)
today = date.today()
diff = (today - birthday).days
print(f"{diff} days since birthday")
# Day of week — 0=Monday, 6=Sunday
print(today.weekday()) # int
print(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][today.weekday()])
# Day name via strftime
print(today.strftime("%A")) # 'Saturday' (or whatever)
# Find next Monday
days_until_monday = (7 - today.weekday()) % 7 or 7
print(today + timedelta(days=days_until_monday))
(a) Get the current time in both UTC and Asia/Seoul, and print the difference (should be 9 hours). Use zoneinfo.ZoneInfo. (b) Compute the date that is exactly 100 days from today. Print it as ISO format. (c) Parse the string "2026-12-25T10:00:00+09:00" with fromisoformat and print how many days from now until that datetime.
Progress
Progress is local-only — sign in to sync across devices.