Phase 5 · Advanced PythonModule 28~32 min read

Dates, Times, Math & Randomness

Work with dates, times, precise numbers, and randomness.

What you'll learn

Almost every program eventually deals with time, numbers, or randomness. Python's standard library covers all three well — from calendar arithmetic to cryptographically strong tokens to exact decimal money math.

By the end of this lesson you'll be able to:

  • Create and inspect dates and times with datetime
  • Do date arithmetic with timedelta
  • Format, parse, and convert time zones
  • Use math, random, and secrets — and know which to reach for
  • Do exact arithmetic with Decimal and Fraction

Dates & times

The datetime module gives you date (a calendar day), time (a wall-clock time), and datetime (both together). Each is immutable and comparable.

dates.py
from datetime import date, datetime

d = date(2024, 8, 26)
print(d)                        # 2024-08-26
print(d.year, d.month, d.day)   # 2024 8 26
print(d.weekday())              # 0  (Mon=0 ... Sun=6) -> Monday

dt = datetime(2024, 8, 26, 9, 30, 0)
print(dt)                       # 2024-08-26 09:30:00
print(dt.hour, dt.minute)       # 9 30

Date arithmetic

A timedelta is a duration. Add one to a date to move forward or back; subtract two dates to get the gap between them. This is how you compute deadlines, ages, and "days remaining."

timedelta.py
from datetime import date, timedelta

start = date(2024, 1, 1)
deadline = start + timedelta(days=90)
print(deadline)                 # 2024-03-31

# Subtracting two dates gives a timedelta
gap = date(2024, 12, 25) - date(2024, 1, 1)
print(gap.days)                 # 359

# timedelta accepts weeks, hours, minutes, seconds...
print(timedelta(weeks=2))       # 14 days, 0:00:00

Tip

Never do date math by hand with day counts — leap years, month lengths, and daylight saving will bite you. Let timedelta and datetime handle the calendar.

Formatting, parsing & zones

strftime turns a datetime into a formatted string; strptime parses a string back into a datetime. For anything user-facing or cross-region, attach a real time zone with zoneinfo.

formatting.py
from datetime import datetime
from zoneinfo import ZoneInfo

dt = datetime(2024, 8, 26, 9, 30)

# Format a datetime -> string  (strftime)
print(dt.strftime("%Y/%m/%d %H:%M"))   # 2024/08/26 09:30
print(dt.strftime("%A, %B %d"))        # Monday, August 26

# Parse a string -> datetime  (strptime)
parsed = datetime.strptime("2024-08-26 09:30", "%Y-%m-%d %H:%M")
print(parsed == dt)                    # True

# Timezone-aware conversion
paris = datetime(2024, 8, 26, 18, 0, tzinfo=ZoneInfo("Europe/Paris"))
print(paris.astimezone(ZoneInfo("UTC")).hour)   # 16  (Paris is UTC+2 in summer)

Watch out

A datetime with no time zone is naive — it doesn't know where it is. For servers and stored timestamps, prefer timezone-aware datetimes (often in UTC) and only convert to local time for display.

math, random & secrets

math holds precise mathematical functions and constants. random generates pseudo-random numbers for games, sampling, and simulations — seed it to make results reproducible.

math.py
import math

print(math.sqrt(144))                  # 12.0
print(math.pi)                         # 3.141592653589793
print(math.ceil(4.1), math.floor(4.9)) # 5 4
print(math.gcd(24, 36))                # 12
print(round(3.14159, 2))               # 3.14
random.py
import random, secrets

random.seed(42)                          # seed -> reproducible results
print(random.randint(1, 6))              # a dice roll in 1..6
print(random.choice(["red", "green"]))   # a random element
print(random.random())                   # a float in [0.0, 1.0)

deck = [1, 2, 3, 4, 5]
random.shuffle(deck)                      # shuffles the list in place

# secrets: cryptographically strong — for tokens, passwords, keys
print(secrets.token_hex(16))             # a 32-char hex token

Key idea

Use random for simulations and games. Use secrets for anything security-sensitive — password reset tokens, session IDs, API keys. random is predictable and must never guard real secrets.

Exact math

Floats are stored in binary, so 0.1 + 0.2 isn't exactly 0.3. That's fine for science, disastrous for money. Reach for Decimal (exact base-10) or Fraction (exact ratios) when precision matters.

precise.py
from decimal import Decimal
from fractions import Fraction

# Floats are BINARY approximations:
print(0.1 + 0.2)                         # 0.30000000000000004

# Decimal is exact for base-10 arithmetic (use it for money!):
print(Decimal("0.1") + Decimal("0.2"))   # 0.3

# Fraction keeps exact ratios:
print(Fraction(1, 3) + Fraction(1, 6))   # 1/2

Recap & quick check

Key takeaways

  • datetime provides date, time, and datetime objects — immutable and comparable.
  • timedelta is a duration: add it to dates to shift them; subtract dates to get the gap.
  • strftime formats a datetime to a string; strptime parses a string to a datetime.
  • Prefer timezone-aware datetimes (zoneinfo) for stored/server times; convert to local only for display.
  • random is for simulations and games (seed for reproducibility); secrets is for security tokens.
  • Use Decimal or Fraction for exact arithmetic — floats are binary approximations (0.1 + 0.2 != 0.3).

Quick check

1. How do you compute the date 90 days after another date?

2. Which method parses a string like '2024-08-26' into a datetime?

3. You need a token for a password-reset link. Which module?

4. Why does 0.1 + 0.2 print 0.30000000000000004?

5. What does a 'naive' datetime lack?

You've now met several standard-library modules. Next we take a wider tour of the toolbox that ships with Python. Next up: Module 29 — The Standard Library Toolbox.