The Four Core Types
The Four Core Types
from datetime import date, time, datetime, timedelta
date(2026, 9, 22) # calendar day only
time(14, 30, 5) # wall-clock time
datetime(2026, 9, 22, 14, 30) # date + time
timedelta(days=7, hours=3) # a duration — the only thing you subtract
due = date.today() + timedelta(days=14)
opened = datetime(2026, 1, 1, 9)
closed = opened + timedelta(minutes=45)
elapsed = closed - opened # timedelta result
timedelta supports days, seconds, microseconds — combining is normalized (1 day + 25 hours = 2 days + 1 hour). Parsing and formatting use format codes: datetime.strptime(s, "%Y-%m-%dT%H:%M:%SZ") and .isoformat() for output. date.today() and datetime.now() read the system local clock; anything serialized to a log or API should be timezone-aware first.
Timezones with zoneinfo
Timezones with zoneinfo
Since Python 3.9 the stdlib has IANA time zones:
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc = datetime.now(timezone.utc) # always store instants in UTC
tokyo = utc.astimezone(ZoneInfo("Asia/Tokyo")) # convert for display
local = datetime(2026, 9, 22, 9, 0, tzinfo=ZoneInfo("America/New_York"))
Rules that keep you safe:
- Aware datetimes carry
tzinfo; naive ones do not. Subtracting aware from naive raisesTypeError astimezone()with no argument converts to the system local zone- On Windows (and slim images), install
tzdata— the IANA database is not bundled - Legacy
pytzrequireslocalize()/normalize(); zoneinfo attaches correctly viatzinfo=
Pitfalls and Interview Angles
Pitfalls and Interview Angles
DST edges. A local wall time can occur twice (fall-back) or not at all (spring-forward). The fold attribute (0 or 1) disambiguates the repeated hour when converting.
Deprecated shortcuts. datetime.utcnow() and utcfromtimestamp() return naive values misread as local — deprecated since 3.12; use datetime.now(timezone.utc).
Monotonic questions. Measuring elapsed time with datetime.now() breaks when the clock is adjusted; use time.perf_counter() or time.monotonic().
Interview angle: store instants as UTC-aware, convert to user zones only at the presentation edge, format with ISO 8601, and explain why %z/%Z behave differently across platforms (offset versus abbreviation).
Quiz
1. What does datetime(2026,9,22) - datetime(2026,9,15) return?
2. Why avoid datetime.utcnow() in new code?
3. What does ZoneInfo("Europe/Berlin") give you for a time two Sundays in October?
Flashcards
Question
Naive vs aware datetime
Click to reveal answer
Answer
Naive has tzinfo=None (offset unknown); aware carries tzinfo and can be converted safely.
Question
timedelta
Click to reveal answer
Answer
Duration in days/seconds/microseconds; the only legal operand for datetime arithmetic.
Question
Store UTC, render local
Click to reveal answer
Answer
Persist instants as UTC-aware; convert with astimezone(ZoneInfo(...)) at the display edge.
Question
DST fold attribute
Click to reveal answer
Answer
fold=0/1 picks the first or second occurrence of an ambiguous local time during fall-back.
Revision Notes
Key Takeaways
- 1. date/time/datetime/timedelta cover distinct jobs; arithmetic only works through timedelta
- 2. zoneinfo (3.9+) provides IANA zones; always create aware datetimes for stored instants
- 3. Use monotonic clocks for durations and ISO 8601 for interchange
Interview Tips
- • State your storage rule (UTC-aware) and rendering rule (user zone) before writing code
- • Handle the DST ambiguity question explicitly with fold and the transition edge case
Cheat Sheet
datetime±timedelta; now(timezone.utc) not utcnow(); zoneinfo (pip install tzdata on Windows); aware+naive raises; ISO 8601 out; perf_counter for durations.