The datetime module has date (a calendar day), datetime (a day and a time) and timedelta (a duration). Subtracting two dates gives a timedelta; adding a timedelta moves a date forward or back.
Convert text to dates with strptime and dates to text with strftime, using codes such as %d (day), %m (month), %Y (year), %A (weekday name) and %B (month name). date.fromisoformat("2026-03-14") parses the standard ISO format directly.
Datetimes without a time zone are "naive". For timestamps that matter (payments, logs), attach a zone. Tanzania uses East Africa Time, UTC+3 all year, so timezone(timedelta(hours=3)) describes it exactly. For zones with daylight saving, use zoneinfo.ZoneInfo("Europe/London") — on Windows, run pip install tzdata first.
from datetime import date, datetime, timedelta, timezone
exam_day = date(2026, 11, 2)
registered = date.fromisoformat("2026-03-14")
print((exam_day - registered).days, "days between registration and exams") # 233
deadline = registered + timedelta(weeks=6)
print("Fee deadline:", deadline.strftime("%A %d %B %Y")) # Saturday 25 April 2026
typed = "14/03/2008" # how people write dates in Tanzania
born = datetime.strptime(typed, "%d/%m/%Y").date()
on = date(2026, 3, 14)
age = on.year - born.year - ((on.month, on.day) < (born.month, born.day))
print("Age on", on.isoformat(), "=", age) # 18
EAT = timezone(timedelta(hours=3), "EAT") # East Africa Time, no daylight saving
paid = datetime(2026, 3, 14, 9, 30, tzinfo=EAT)
print(paid.isoformat()) # 2026-03-14T09:30:00+03:00
print(paid.astimezone(timezone.utc).strftime("%H:%M %Z")) # 06:30 UTC
school_days = [registered + timedelta(days=i) for i in range(7)]
print([d.strftime("%a %d") for d in school_days if d.weekday() < 5])Key points
date,datetimeandtimedeltacover days, moments and durations.strptimeparses text;strftimeformats; ISO dates parse withfromisoformat.- Attach a time zone to important timestamps; EAT is a fixed UTC+3.
Exercise
Ask for a student's date of birth in DD/MM/YYYY format with input(), then print their age today in years and the weekday they were born on. Print a friendly message instead of crashing if the date is invalid.
Show solution
Try the exercise yourself first — then compare your approach with this one.
strptime raises ValueError for anything that isn't a real date in the right format, so the try/except turns that into a friendly message, and a date after today gets its own message. The age calculation subtracts one year if this year's birthday hasn't happened yet.
from datetime import date, datetime
def age_on(born: date, today: date) -> int:
return today.year - born.year - ((today.month, today.day) < (born.month, born.day))
text = input("Date of birth (DD/MM/YYYY): ")
try:
born = datetime.strptime(text.strip(), "%d/%m/%Y").date()
except ValueError:
print(f"Sorry, '{text}' is not a valid date like 14/03/2008.")
else:
today = date.today()
if born > today:
print("That date is in the future.")
else:
print(f"You are {age_on(born, today)} years old.")
print(f"You were born on a {born.strftime('%A')}.")