Chapters
Python114 chapters

Modules and the standard libraryChapter 72 of 114

Dates

Points in time, differences between them, and turning them into text.

The three types

datetime gives you date (a calendar day), time (a clock time), and datetime (both):

Python
from datetime import date, time, datetime

print(date(2026, 3, 14))
print(time(9, 30))
print(datetime(2026, 3, 14, 9, 30))

Output

2026-03-14
09:30:00
2026-03-14 09:30:00

Printing gives ISO format, which sorts correctly as text — a genuinely useful property.

Now

Python
from datetime import datetime, date

now = datetime.now()
print(type(now).__name__)
print(date.today().year > 2000)

Output

datetime
True

Reading the parts

Python
from datetime import datetime

moment = datetime(2026, 3, 14, 9, 30, 45)
print(moment.year, moment.month, moment.day)
print(moment.hour, moment.minute)
print(moment.weekday())
print(moment.date())

Output

2026 3 14
9 30
5
2026-03-14

weekday() counts from Monday as 0, so 5 is Saturday. isoweekday() counts from Monday as 1, which is the other convention you will meet.

Formatting with strftime

Python
from datetime import datetime

moment = datetime(2026, 3, 14, 9, 5)
print(moment.strftime("%d/%m/%Y"))
print(moment.strftime("%A %d %B %Y"))
print(moment.strftime("%H:%M"))
print(moment.strftime("%Y-%m-%d %H:%M:%S"))

Output

14/03/2026
Saturday 14 March 2026
09:05
2026-03-14 09:05:00
CodeMeans
%Yfour-digit year
%mmonth as 01 to 12
%dday as 01 to 31
%Hhour, 24-hour
%Mminute
%Bmonth name
%Aweekday name

Parsing with strptime

The same codes, in reverse:

Python
from datetime import datetime

moment = datetime.strptime("14/03/2026", "%d/%m/%Y")
print(moment)
print(moment.year)

Output

2026-03-14 00:00:00
2026

The format string has to match the text exactly, character for character. A mismatch raises ValueError rather than guessing.

For ISO text, there is a shortcut that needs no format string:

Python
from datetime import datetime, date

print(datetime.fromisoformat("2026-03-14T09:30:00"))
print(date.fromisoformat("2026-03-14"))
print(date(2026, 3, 14).isoformat())

Output

2026-03-14 09:30:00
2026-03-14
2026-03-14

Differences

Subtracting two dates gives a timedelta:

Python
from datetime import date, timedelta

start = date(2026, 3, 1)
end = date(2026, 3, 14)
gap = end - start

print(gap)
print(gap.days)
print(start + timedelta(days=30))
print(start - timedelta(weeks=2))

Output

13 days, 0:00:00
13
2026-03-31
2026-02-15

timedelta takes days, weeks, hours, minutes and seconds — but not months or years, because those are not fixed lengths. For "one month later", use the dateutil package.

Comparing

Python
from datetime import date

print(date(2026, 1, 1) < date(2026, 6, 1))
print(sorted([date(2026, 5, 1), date(2026, 2, 1)]))

Output

True
[datetime.date(2026, 2, 1), datetime.date(2026, 5, 1)]

Note the list shows the repr, which is why it looks different from a printed date.

Time zones

A datetime with no zone is naive: it does not know where it is. Comparing a naive one with an aware one raises:

Python
from datetime import datetime, timezone, timedelta

aware = datetime(2026, 3, 14, 9, 0, tzinfo=timezone.utc)
print(aware)
print(aware.astimezone(timezone(timedelta(hours=2))))

naive = datetime(2026, 3, 14, 9, 0)
try:
    print(naive < aware)
except TypeError as problem:
    print("TypeError:", problem)

Output

2026-03-14 09:00:00+00:00
2026-03-14 11:00:00+02:00
TypeError: can't compare offset-naive and offset-aware datetimes

Test yourself

2 questions

Why can a timedelta not take months or years?

Show the answer

They are not fixed lengths — A month is 28 to 31 days. For calendar arithmetic use the dateutil package.

What happens when you compare a naive datetime with an aware one?

Show the answer

TypeError — Store and compute in UTC and convert only for display, and this stops coming up.

Next chapter

Math

The math module, plus statistics and random.