Python Date & Time — datetime, time, calendar
Python ships three complementary modules for working with dates and times:
datetime— high-level objects for dates, times, and durations. This is what you reach for most.time— lower-level, OS-facing functions (timestamps, sleeping, performance timers).calendar— calendar-related helpers (leap years, weekday names, month grids).
import datetime, time, calendar
print(datetime.date.today()) # 2025-01-31
print(time.time()) # 1738291200.123 (seconds since epoch)
print(calendar.isleap(2024)) # TrueThe datetime module
Section titled “The datetime module”It defines four key classes:
| Class | Represents |
|---|---|
date | A calendar date — year, month, day. |
time | A time of day — hour, minute, second, microsecond. |
datetime | A date and a time combined. |
timedelta | A duration — the difference between two dates/times. |
Creating dates and times
Section titled “Creating dates and times”from datetime import date, time, datetime
d = date(2025, 1, 31)
print(d.year, d.month, d.day) # 2025 1 31
t = time(14, 30, 15)
print(t.hour, t.minute) # 14 30
dt = datetime(2025, 1, 31, 14, 30, 15)
print(dt) # 2025-01-31 14:30:15
# "Now" helpers
print(date.today()) # today's date
print(datetime.now()) # local date + time right nowAccessing parts
Section titled “Accessing parts”from datetime import datetime
dt = datetime(2025, 1, 31, 14, 30, 15)
print(dt.date()) # 2025-01-31
print(dt.time()) # 14:30:15
print(dt.weekday()) # 4 (Mon=0 ... Sun=6)
print(dt.isoweekday()) # 5 (Mon=1 ... Sun=7)
print(dt.isoformat()) # 2025-01-31T14:30:15Formatting with strftime
Section titled “Formatting with strftime”strftime (“string format time”) turns a date/time into a string using format codes.
| Code | Meaning | Example |
|---|---|---|
%Y | 4-digit year | 2025 |
%y | 2-digit year | 25 |
%m | Month, zero-padded | 01 |
%B | Full month name | January |
%b | Abbreviated month | Jan |
%d | Day of month | 31 |
%A | Full weekday name | Friday |
%a | Abbreviated weekday | Fri |
%H | Hour (24-hour) | 14 |
%I | Hour (12-hour) | 02 |
%M | Minute | 30 |
%S | Second | 15 |
%p | AM / PM | PM |
%j | Day of the year | 031 |
from datetime import datetime
dt = datetime(2025, 1, 31, 14, 30, 15)
print(dt.strftime("%Y-%m-%d")) # 2025-01-31
print(dt.strftime("%A, %B %d, %Y")) # Friday, January 31, 2025
print(dt.strftime("%I:%M %p")) # 02:30 PMParsing with strptime
Section titled “Parsing with strptime”strptime (“string parse time”) does the reverse — it reads a string into a datetime, given a format that describes its layout.
from datetime import datetime
s = "2025-01-31 14:30"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M")
print(dt) # 2025-01-31 14:30:00
print(type(dt)) # <class 'datetime.datetime'>
# ISO strings have a dedicated fast parser:
print(datetime.fromisoformat("2025-01-31T14:30:15"))Date arithmetic with timedelta
Section titled “Date arithmetic with timedelta”A timedelta is a span of time. Add or subtract it from dates; subtract two dates to get a timedelta.
from datetime import date, datetime, timedelta
today = date(2025, 1, 31)
week_later = today + timedelta(days=7)
print(week_later) # 2025-02-07
start = datetime(2025, 1, 1, 9, 0)
end = datetime(2025, 1, 1, 17, 30)
worked = end - start
print(worked) # 8:30:00
print(worked.total_seconds()) # 30600.0
# timedelta accepts weeks, days, hours, minutes, seconds
print(timedelta(weeks=2, days=3)) # 17 days, 0:00:00Time zones (aware vs naive)
Section titled “Time zones (aware vs naive)”A datetime with no time zone is naive; one carrying tzinfo is aware. Prefer aware datetimes for anything crossing zones. Since Python 3.9 the standard library includes zoneinfo.
from datetime import datetime, timezone, timedelta
from zoneinfo import ZoneInfo
# UTC-aware "now"
now_utc = datetime.now(timezone.utc)
print(now_utc.tzinfo) # UTC
# Convert between zones
ny = datetime(2025, 1, 31, 12, 0, tzinfo=ZoneInfo("America/New_York"))
tokyo = ny.astimezone(ZoneInfo("Asia/Tokyo"))
print(tokyo) # 2025-02-01 02:00:00+09:00The time module
Section titled “The time module”Lower-level utilities tied to the operating system clock.
| Function | Purpose |
|---|---|
time.time() | Seconds since the epoch (a float timestamp). |
time.sleep(secs) | Pause execution. |
time.localtime() | Convert a timestamp to a local struct_time. |
time.gmtime() | Convert a timestamp to a UTC struct_time. |
time.strftime(fmt, t) | Format a struct_time. |
time.perf_counter() | High-resolution timer for benchmarking. |
import time
start = time.perf_counter()
time.sleep(0.1) # pause 100 ms
elapsed = time.perf_counter() - start
print(f"Slept for {elapsed:.3f}s") # Slept for 0.100s
ts = time.time()
print(time.strftime("%Y-%m-%d", time.localtime(ts)))Use
perf_counter()to measure durations, andtime()to get a timestamp. Never usetime()for benchmarking — it can jump if the system clock changes.
The calendar module
Section titled “The calendar module”Helpers for reasoning about months, weeks, and leap years.
| Function | Returns |
|---|---|
calendar.isleap(year) | True if the year is a leap year. |
calendar.monthrange(y, m) | (first_weekday, num_days) for that month. |
calendar.weekday(y, m, d) | Weekday index (Mon=0). |
calendar.month(y, m) | A text calendar for the month. |
calendar.day_name[i] | Full weekday name for index i. |
import calendar
print(calendar.isleap(2024)) # True
print(calendar.monthrange(2025, 2)) # (5, 28) -> starts Sat, 28 days
print(calendar.day_name[0]) # Monday
# Print a whole month grid
print(calendar.month(2025, 1))Putting it together
Section titled “Putting it together”from datetime import date
def days_until_birthday(birth_month, birth_day):
today = date.today()
this_year = date(today.year, birth_month, birth_day)
next_bday = this_year if this_year >= today else date(today.year + 1, birth_month, birth_day)
return (next_bday - today).days
print(days_until_birthday(12, 25)) # days until the next Dec 25Common pitfalls
Section titled “Common pitfalls”- Mixing naive and aware datetimes raises
TypeErrorwhen you subtract them. Pick one and stick with it. weekday()vsisoweekday()— one starts Monday at 0, the other at 1.strptimeformat must match exactly, including separators, or it raisesValueError.time.sleepblocks the whole thread — fine for scripts, but use async patterns in servers.
Practice Exercises
Section titled “Practice Exercises”Exercise 1 – Format today’s date
Section titled “Exercise 1 – Format today’s date”Exercise 2 – Days between two dates
Section titled “Exercise 2 – Days between two dates”Exercise 3 – Is it a leap year?
Section titled “Exercise 3 – Is it a leap year?”Summary
Section titled “Summary”- Use
datetimefor dates, times, durations (timedelta), and arithmetic. - Format with
strftime, parse withstrptime/fromisoformat. - Prefer aware datetimes (
timezone.utc,zoneinfo.ZoneInfo) when zones matter. timegives timestamps, sleeping, andperf_counterfor benchmarks.calendaranswers leap-year, weekday, and month-grid questions.
pch.coffeeTagline
pch.coffeeCtapch.feedbackHeading
pch.feedbackSubheading