Skip to content

datetime Interview Questions & Answers

15 questions Updated 2026-06-18 Share:

Python interview questions on datetime vs date vs time, naive vs timezone-aware datetimes with zoneinfo, strftime/strptime, timedelta arithmetic, and the now() vs utcnow() pitfall.

Read the in-depth guidePython datetime Explained — date, time, timedelta, Timezones, and Parsing(opens in new tab)
15 of 15

The datetime module provides three core types. date holds a calendar date (year, month, day) with no time. time holds a time of day (hour, minute, second, microsecond) with no date. datetime combines both into a single timestamp.

from datetime import date, time, datetime

d = date(2026, 6, 18)               # just the date
t = time(14, 30, 0)                 # just the time of day
dt = datetime(2026, 6, 18, 14, 30)  # date + time together

dt.date()                           # -> date(2026, 6, 18)
dt.time()                           # -> time(14, 30)
date.today()                        # current date

Use date for things like birthdays or due dates where time is irrelevant, time for a recurring clock time, and datetime for actual events/timestamps. Most real-world work uses datetime.

A naive datetime has no timezone info (tzinfo is None) — it's just wall clock numbers with no reference point, so it's ambiguous. An aware datetime carries a tzinfo, pinning it to an actual instant. Use the stdlib zoneinfo module (Python 3.9+) to attach real IANA timezones.

from datetime import datetime
from zoneinfo import ZoneInfo

naive = datetime(2026, 6, 18, 14, 30)          # ambiguous — no tz
aware = datetime(2026, 6, 18, 14, 30,
                 tzinfo=ZoneInfo("America/New_York"))

utc = aware.astimezone(ZoneInfo("UTC"))        # convert between zones

You can't compare or subtract a naive and an aware datetime — it raises TypeError. Best practice: store and compute in UTC-aware datetimes, and convert to local zones only for display.

They are inverses. strftime ("string from time") formats a datetime into a string using format codes. strptime ("string parse time") parses a string into a datetime using a matching format.

from datetime import datetime

dt = datetime(2026, 6, 18, 14, 30)
s = dt.strftime("%Y-%m-%d %H:%M")       # datetime -> "2026-06-18 14:30"

parsed = datetime.strptime("2026-06-18 14:30",
                           "%Y-%m-%d %H:%M")  # str -> datetime

Common codes: %Y (4-digit year), %m (month), %d (day), %H (24-hour), %M (minute), %S (second). To remember: f = format (out), p = parse (in). For standard ISO strings, datetime.fromisoformat() / .isoformat() are simpler.

A timedelta represents a duration — a difference between two points in time. Subtracting two datetimes yields a timedelta; adding a timedelta to a datetime shifts it. A timedelta stores days, seconds, and microseconds.

from datetime import datetime, timedelta

start = datetime(2026, 6, 18, 9, 0)
end   = datetime(2026, 6, 18, 17, 30)

worked = end - start              # timedelta(seconds=30600)
worked.total_seconds()            # 30600.0
worked.seconds // 3600            # 8 (hours portion)

tomorrow = start + timedelta(days=1)      # shift forward
week_ago = start - timedelta(weeks=1)     # shift back

Use total_seconds() to get the whole duration as a number (the .seconds attribute is only the sub-day part). timedelta makes date math safe — it correctly rolls over months and years.

The big trap: both datetime.now() and the old datetime.utcnow() return naive datetimes. now() gives local wall time, utcnow() gives the UTC wall time — but neither attaches a tzinfo, so a utcnow() value silently looks like local time and corrupts later conversions. utcnow() is deprecated in modern Python.

from datetime import datetime
from zoneinfo import ZoneInfo

datetime.now()                       # naive, local time — ambiguous
datetime.utcnow()                    # naive, but labelled nothing! (deprecated)

# correct: an AWARE UTC timestamp
now_utc = datetime.now(ZoneInfo("UTC"))
local = datetime.now(ZoneInfo("America/New_York"))

Rule of thumb: always pass a timezone to now() to get an aware datetime, and avoid utcnow() entirely. Store timestamps as UTC-aware and convert for display.

Use datetime.fromisoformat() to parse and .isoformat() to produce ISO 8601 strings — simpler and faster than strptime/strftime for the standard format. Python 3.11+ parses a much wider range (including Z suffix).

from datetime import datetime

dt = datetime.fromisoformat("2026-06-18T14:30:00+00:00")
dt.isoformat()        # '2026-06-18T14:30:00+00:00'
datetime.fromisoformat("2026-06-18T14:30:00Z")   # 3.11+ accepts 'Z'

Rule of thumb: prefer fromisoformat/isoformat for ISO strings (APIs, JSON, databases); reserve strptime/strftime for non-standard custom formats.

.timestamp() converts an aware datetime to a Unix epoch float (seconds since 1970 UTC); datetime.fromtimestamp(ts, tz) converts back. For naive datetimes, .timestamp() assumes local time — another reason to stay aware.

from datetime import datetime
from zoneinfo import ZoneInfo

dt = datetime(2026, 6, 18, 14, 30, tzinfo=ZoneInfo("UTC"))
ts = dt.timestamp()                          # 1781879400.0
datetime.fromtimestamp(ts, ZoneInfo("UTC"))  # back to the datetime

Rule of thumb: always pass a tz to fromtimestamp and use aware datetimes with .timestamp() to avoid silent local-time assumptions.

zoneinfo applies the correct UTC offset for the date, so DST is handled automatically — but arithmetic in local time can land on ambiguous (fall-back) or nonexistent (spring-forward) times. Do math in UTC, then convert.

from datetime import datetime, timedelta
from zoneinfo import ZoneInfo

ny = ZoneInfo("America/New_York")
before = datetime(2026, 3, 8, 1, 30, tzinfo=ny)   # just before spring-forward
# adding 1 hour in local time may skip the 2 AM that doesn't exist
utc = before.astimezone(ZoneInfo("UTC")) + timedelta(hours=1)
utc.astimezone(ny)                                 # correct wall time

Rule of thumb: store/compute in UTC and convert to local only for display — never do duration math directly on DST-affected local datetimes.

Memorize the everyday codes: %Y/%y (4-/2-digit year), %m month, %d day, %H 24-hour / %I 12-hour, %M minute, %S second, %p AM/PM, %A/%a weekday name, %B/%b month name, %z UTC offset, %j day-of-year.

from datetime import datetime
dt = datetime(2026, 6, 18, 14, 30)
dt.strftime("%A, %B %d, %Y")     # 'Thursday, June 18, 2026'
dt.strftime("%I:%M %p")          # '02:30 PM'
datetime.strptime("06/18/26", "%m/%d/%y")

Rule of thumb: %Y-%m-%d %H:%M:%S covers most needs; case matters (%M minute vs %m month, %H 24h vs %I 12h).

date/time/datetime are immutable (and hashable, so usable as dict keys). To get a changed version, use .replace(), which returns a new object with the given fields swapped.

from datetime import datetime
dt = datetime(2026, 6, 18, 14, 30)
midnight = dt.replace(hour=0, minute=0)   # new datetime
dt                                         # unchanged

# attach a timezone to a naive datetime:
from zoneinfo import ZoneInfo
aware = dt.replace(tzinfo=ZoneInfo("UTC"))

Rule of thumb: datetimes never mutate — use .replace() for tweaks and timedelta arithmetic for shifts; note .replace(tzinfo=...) labels without converting.

Use datetime.now(timezone.utc) (or ZoneInfo("UTC")) to get an aware UTC timestamp. utcnow()/utcfromtimestamp() are deprecated in 3.12+ precisely because they return naive values that misrepresent UTC as local.

from datetime import datetime, timezone

datetime.now(timezone.utc)        # aware UTC — recommended
# NOT: datetime.utcnow()          # deprecated, returns naive

Rule of thumb: replace every utcnow() with now(timezone.utc) to get a correct, tz-aware UTC timestamp.

Datetimes support the comparison operators and sort chronologically, so sorted(), min, and max work directly. The only rule: you cannot compare naive with aware datetimes — it raises TypeError.

from datetime import datetime
events = [datetime(2026, 6, 18), datetime(2026, 1, 1), datetime(2026, 12, 31)]
sorted(events)        # chronological order
max(events)           # latest

# datetime(2026,1,1) < datetime(2026,1,1, tzinfo=utc)  # TypeError!

Rule of thumb: keep all datetimes consistently naive or consistently aware before comparing/sorting — mixing the two errors out.

Use the lower-level time module for epoch seconds, sleeping, and performance measurement. time.time() gives wall-clock epoch; time.perf_counter() and time.monotonic() are for measuring durations (immune to clock changes).

import time
start = time.perf_counter()
time.sleep(0.1)
elapsed = time.perf_counter() - start   # high-resolution duration

time.time()          # Unix epoch seconds (wall clock)
time.monotonic()     # never goes backwards — good for timeouts

Rule of thumb: datetime for calendar dates/times; time.perf_counter/monotonic for measuring elapsed time, and time.sleep to pause.

date.weekday() returns 0=Monday..6=Sunday (isoweekday() is 1=Monday..7=Sunday). The calendar module gives month/year grids, leap-year checks, and month lengths.

from datetime import date
import calendar

d = date(2026, 6, 18)
d.weekday()                 # 3 (Thursday)
d.isoweekday()              # 4
calendar.isleap(2024)       # True
calendar.monthrange(2026, 6)  # (0, 30) -> (first weekday, days in month)

Rule of thumb: weekday()/isoweekday() for day-of-week logic; reach for the calendar module for month lengths, leap years, and calendar layouts.

Either parse an offset-bearing ISO string with fromisoformat, or parse a naive datetime and attach a zone with .replace(tzinfo=...) (label) or .astimezone() (convert). strptime with %z reads explicit offsets.

from datetime import datetime
from zoneinfo import ZoneInfo

datetime.fromisoformat("2026-06-18T14:30+05:30")     # aware directly
datetime.strptime("2026-06-18 +0530", "%Y-%m-%d %z") # %z reads the offset

naive = datetime(2026, 6, 18, 14, 30)
naive.replace(tzinfo=ZoneInfo("Asia/Kolkata"))       # label as that zone

Rule of thumb: use %z/fromisoformat when the string carries an offset; use .replace(tzinfo=...) to label a naive value as a known zone (no time shift).

More ways to practice

The self-quiz is live. Join our channel for updates, new content & tech tips.

Join our WhatsApp Channel