Understanding Python Datetime Module
Learn how to work with dates and times in Python using the datetime module: date, time, datetime, timedelta, strftime, strptime, and time zones.
Python does not have a dedicated built-in date type. Instead, the standard library's datetime module provides a complete toolkit for creating, manipulating, formatting, and parsing dates and times. This chapter covers all the core classes — date, time, datetime, timedelta, and timezone — and shows practical patterns you will use regularly.
Importing the Module
The datetime module is part of the standard library and requires no installation. You can import it in two common ways:
# Import the module and qualify every name
import datetime
today = datetime.date.today()
# Import specific classes directly
from datetime import date, time, datetime, timedelta, timezone
today = date.today()The from datetime import ... style is shorter in practice and is used throughout this chapter.
The date Class
date represents a calendar date (year, month, day) with no time-of-day component.
Creating date Objects
Accessing Date Attributes
Once you have a date object you can read its year, month, and day as integer attributes, and ask which day of the week it falls on:
from datetime import date
d = date(2024, 6, 15)
print(d.year) # 2024
print(d.month) # 6
print(d.day) # 15
# weekday(): Monday = 0, Sunday = 6
print(d.weekday()) # 5 (Saturday)
# isoweekday(): Monday = 1, Sunday = 7
print(d.isoweekday()) # 6 (Saturday)The time Class
time represents a time of day (hour, minute, second, microsecond) independent of any particular date.
from datetime import time
# time(hour, minute, second) — all arguments optional, default to 0
t = time(14, 30, 0)
print(t) # 14:30:00
print(t.hour) # 14
print(t.minute) # 30
print(t.second) # 0The time class is most useful when you need to store or compare clock times without caring about the date, for example "remind me at 09:00 every day."
The datetime Class
datetime is the workhorse class. It combines a full date and a time-of-day into one object and is what you will use in most real programs.
Getting the Current Date and Time
from datetime import datetime
# Local system time (naive — no time zone)
now = datetime.now()
print(now) # e.g. 2024-06-15 14:30:45.123456
# UTC time
utc_now = datetime.utcnow()
print(utc_now) # e.g. 2024-06-15 18:30:45.123456Creating datetime Objects
from datetime import datetime, date, time
# Constructor: datetime(year, month, day, hour=0, minute=0, second=0)
dt = datetime(2024, 6, 15, 14, 30, 45)
print(dt) # 2024-06-15 14:30:45
# From an ISO 8601 string
dt2 = datetime.fromisoformat("2024-06-15T14:30:45")
print(dt2) # 2024-06-15 14:30:45
# Combine a date and a time object
combined = datetime.combine(date(2024, 6, 15), time(14, 30, 0))
print(combined) # 2024-06-15 14:30:00Accessing datetime Attributes
datetime exposes all attributes from both date and time:
from datetime import datetime
dt = datetime(2024, 6, 15, 14, 30, 45)
print(dt.year) # 2024
print(dt.month) # 6
print(dt.day) # 15
print(dt.hour) # 14
print(dt.minute) # 30
print(dt.second) # 45
# Extract just the date or time part
print(dt.date()) # 2024-06-15
print(dt.time()) # 14:30:45The timedelta Class
timedelta represents a duration — the difference between two points in time. You use it to add or subtract spans of time from date and datetime objects.
Creating and Using timedelta
from datetime import date, timedelta
today = date(2024, 6, 15)
# Add 30 days
future = today + timedelta(days=30)
print(future) # 2024-07-15
# Subtract 7 days
last_week = today - timedelta(weeks=1)
print(last_week) # 2024-06-08
# timedelta can express days, seconds, and microseconds
# Convenience arguments: days, seconds, microseconds, milliseconds, minutes, hours, weeks
delta = timedelta(hours=2, minutes=30)
print(delta) # 2:30:00Calculating the Difference Between Two Dates
Subtracting one date or datetime from another returns a timedelta:
from datetime import date
start = date(2024, 1, 1)
end = date(2024, 6, 15)
diff = end - start
print(diff) # 166 days, 0:00:00
print(diff.days) # 166This is the standard way to calculate how many days between two dates. Use .total_seconds() on a timedelta if you need the span in seconds.
Formatting Dates and Times (strftime)
strftime ("string format time") converts a date or datetime object into a human-readable string. You pass a format string that contains directives starting with %.
from datetime import datetime
dt = datetime(2024, 6, 15, 14, 30, 45)
print(dt.strftime("%Y-%m-%d")) # 2024-06-15
print(dt.strftime("%d/%m/%Y")) # 15/06/2024
print(dt.strftime("%A, %B %d, %Y")) # Saturday, June 15, 2024
print(dt.strftime("%I:%M %p")) # 02:30 PM
print(dt.strftime("%Y-%m-%d %H:%M:%S")) # 2024-06-15 14:30:45Common strftime Directives
| Directive | Meaning | Example |
|---|---|---|
%Y | 4-digit year | 2024 |
%y | 2-digit year | 24 |
%m | Month as zero-padded number | 06 |
%B | Full month name | June |
%b | Abbreviated month name | Jun |
%d | Day of month, zero-padded | 15 |
%A | Full weekday name | Saturday |
%a | Abbreviated weekday name | Sat |
%H | Hour (24-hour clock) | 14 |
%I | Hour (12-hour clock) | 02 |
%M | Minute | 30 |
%S | Second | 45 |
%p | AM or PM | PM |
%j | Day of the year | 167 |
%W | Week number of the year | 24 |
Parsing Dates and Times (strptime)
strptime ("string parse time") is the reverse of strftime: it converts a string into a datetime object. You must provide a format string that matches the input.
A common gotcha: strptime always returns a datetime, even when the string only contains a date. Call .date() on the result if you need a plain date object.
ISO 8601 Format
The ISO 8601 standard (YYYY-MM-DDTHH:MM:SS) is the most portable way to exchange date and time values. Python has built-in helpers for it:
from datetime import datetime
dt = datetime(2024, 6, 15, 14, 30, 45)
# Produce ISO 8601 string
print(dt.isoformat()) # 2024-06-15T14:30:45
# Parse ISO 8601 string (Python 3.7+)
dt2 = datetime.fromisoformat("2024-06-15T14:30:45")
print(dt2) # 2024-06-15 14:30:45Working with Timestamps
A Unix timestamp is the number of seconds elapsed since 1 January 1970 00:00:00 UTC. Python can convert between timestamps and datetime objects:
Time Zones
By default, datetime.now() returns a naive datetime — it has no time zone information attached. Attaching a tzinfo object makes it aware. Aware datetimes are essential whenever your program handles users in multiple time zones or stores timestamps in a database.
Using the Built-in timezone
datetime.timezone provides timezone.utc and lets you create fixed-offset zones:
from datetime import datetime, timezone, timedelta
# Create an aware UTC datetime
utc_dt = datetime(2024, 6, 15, 14, 30, 45, tzinfo=timezone.utc)
print(utc_dt) # 2024-06-15 14:30:45+00:00
# Create a fixed +5:30 (India Standard Time) offset
ist_offset = timezone(timedelta(hours=5, minutes=30))
ist_dt = utc_dt.astimezone(ist_offset)
print(ist_dt) # 2024-06-15 20:00:45+05:30Using zoneinfo (Python 3.9+)
For real IANA time zones such as America/New_York or Asia/Tokyo, use the built-in zoneinfo module (Python 3.9+). It handles daylight-saving time automatically.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
# UTC aware datetime
utc_dt = datetime(2024, 6, 15, 14, 30, 45, tzinfo=timezone.utc)
# Convert to Eastern Time (handles DST automatically)
eastern = ZoneInfo("America/New_York")
eastern_dt = utc_dt.astimezone(eastern)
print(eastern_dt) # 2024-06-15 10:30:45-04:00
# Convert to Tokyo time
tokyo = ZoneInfo("Asia/Tokyo")
tokyo_dt = utc_dt.astimezone(tokyo)
print(tokyo_dt) # 2024-06-15 23:30:45+09:00On Python 3.8 and earlier, install the third-party pytz library for IANA zone support.
Replacing Components
replace() returns a new object with specific fields changed. The original is never mutated.
from datetime import datetime
dt = datetime(2024, 6, 15, 14, 30, 45)
# Change only the year
dt2 = dt.replace(year=2025)
print(dt2) # 2025-06-15 14:30:45
# Change hour and minute
dt3 = dt.replace(hour=9, minute=0, second=0)
print(dt3) # 2024-06-15 09:00:00Comparing Dates and Times
date and datetime objects support all standard comparison operators:
from datetime import date
d1 = date(2024, 1, 1)
d2 = date(2024, 6, 15)
print(d1 < d2) # True
print(d1 == d2) # False
# Find the earliest date
earliest = min(d1, d2)
print(earliest) # 2024-01-01Only compare aware datetimes with aware datetimes and naive with naive — mixing them raises a TypeError.
Putting It All Together
Here is a practical example that combines several concepts: it calculates how many days remain until a future deadline and formats both dates for display.
from datetime import date
deadline = date(2024, 12, 31)
today = date(2024, 6, 15)
days_left = (deadline - today).days
print(f"Today: {today.strftime('%B %d, %Y')}") # June 15, 2024
print(f"Deadline: {deadline.strftime('%B %d, %Y')}") # December 31, 2024
print(f"Days remaining: {days_left}") # 199Quick Reference
| Task | Code |
|---|---|
| Today's date | date.today() |
| Current date and time | datetime.now() |
| Specific date | date(2024, 6, 15) |
| Date from string | datetime.strptime(s, fmt) |
| Date to string | dt.strftime(fmt) |
| ISO format | dt.isoformat() / datetime.fromisoformat(s) |
| Add/subtract days | d + timedelta(days=N) |
| Days between dates | (d2 - d1).days |
| Convert time zone | dt.astimezone(ZoneInfo("Zone/Name")) |