Python Dates
Learn how to work with dates and times in Python using the datetime module.
Python Dates
A date in Python is not a data type of its own, but we can import a module named datetime to work with dates as date objects.
Example - Import the datetime module and display the current date:
import datetime
x = datetime.datetime.now()
print(x)Date Output
When we executed the code from the example above the result was:
2023-12-07 14:30:59.123456
The date contains year, month, day, hour, minute, second, and microsecond.
The datetime module has many methods to return information about the date object.
Example - Return the year and name of weekday:
import datetime
x = datetime.datetime.now()
print(x.year)
print(x.strftime("%A"))Creating Date Objects
To create a date, we can use the datetime() class (constructor) of the datetime module.
The datetime() class requires three parameters to create a date: year, month, day.
Example - Create a date object:
import datetime
x = datetime.datetime(2020, 5, 17)
print(x)The datetime() class also takes parameters for time and timezone (hour, minute, second, microsecond, tzone), but they are optional, and has a default value of 0, (None for timezone).
The strftime() Method
The datetime object has a method for formatting date objects into readable strings.
The method is called strftime(), and takes one parameter, format, to specify the format of the returned string:
Example - Display the name of the month:
import datetime
x = datetime.datetime(2018, 6, 1)
print(x.strftime("%B"))Format Codes
A reference of all the legal format codes:
Working with Different Date Components
Date Only
import datetime
# Create date only
today = datetime.date.today()
print(today) # 2023-12-07
# Create specific date
birthday = datetime.date(1990, 5, 15)
print(birthday) # 1990-05-15
# Access date components
print(f"Year: {today.year}")
print(f"Month: {today.month}")
print(f"Day: {today.day}")
print(f"Weekday: {today.weekday()}") # Monday is 0Time Only
import datetime
# Create time only
current_time = datetime.time(14, 30, 45)
print(current_time) # 14:30:45
# With microseconds
precise_time = datetime.time(14, 30, 45, 123456)
print(precise_time) # 14:30:45.123456
# Access time components
print(f"Hour: {current_time.hour}")
print(f"Minute: {current_time.minute}")
print(f"Second: {current_time.second}")DateTime Combined
import datetime
# Current date and time
now = datetime.datetime.now()
print(now)
# Specific date and time
event = datetime.datetime(2023, 12, 25, 18, 30, 0)
print(event)
# Combine date and time objects
date_part = datetime.date(2023, 12, 25)
time_part = datetime.time(18, 30, 0)
combined = datetime.datetime.combine(date_part, time_part)
print(combined)Date Arithmetic
You can perform arithmetic operations on dates using timedelta:
Example - Date arithmetic:
import datetime
# Current date
today = datetime.date.today()
print(f"Today: {today}")
# Add days
future_date = today + datetime.timedelta(days=30)
print(f"30 days from now: {future_date}")
# Subtract days
past_date = today - datetime.timedelta(days=7)
print(f"7 days ago: {past_date}")
# Add weeks
next_week = today + datetime.timedelta(weeks=1)
print(f"Next week: {next_week}")
# Complex timedelta
complex_delta = datetime.timedelta(
days=7,
hours=3,
minutes=30,
seconds=45
)
future_datetime = datetime.datetime.now() + complex_delta
print(f"Future datetime: {future_datetime}")
# Calculate difference between dates
date1 = datetime.date(2023, 1, 1)
date2 = datetime.date(2023, 12, 31)
difference = date2 - date1
print(f"Days between: {difference.days}")
print(f"Total seconds: {difference.total_seconds()}")Parsing Dates from Strings
Convert string representations to datetime objects:
Example - Parse dates from strings:
import datetime
# Parse common date formats
date_str1 = "2023-12-07"
parsed_date1 = datetime.datetime.strptime(date_str1, "%Y-%m-%d")
print(parsed_date1)
date_str2 = "December 7, 2023"
parsed_date2 = datetime.datetime.strptime(date_str2, "%B %d, %Y")
print(parsed_date2)
date_str3 = "07/12/2023 14:30:45"
parsed_date3 = datetime.datetime.strptime(date_str3, "%d/%m/%Y %H:%M:%S")
print(parsed_date3)
# Handle different formats
date_formats = [
"%Y-%m-%d",
"%d/%m/%Y",
"%m-%d-%Y",
"%B %d, %Y"
]
date_string = "12-07-2023"
for fmt in date_formats:
try:
parsed = datetime.datetime.strptime(date_string, fmt)
print(f"Successfully parsed with format {fmt}: {parsed}")
break
except ValueError:
continue
else:
print("Could not parse date string")Working with Timezones
Handle timezone-aware datetime objects:
Example - Timezone handling:
import datetime
import pytz # pip install pytz
# Create timezone-aware datetime
utc = pytz.UTC
eastern = pytz.timezone('US/Eastern')
pacific = pytz.timezone('US/Pacific')
# Current time in UTC
utc_now = datetime.datetime.now(utc)
print(f"UTC: {utc_now}")
# Convert to different timezones
eastern_time = utc_now.astimezone(eastern)
pacific_time = utc_now.astimezone(pacific)
print(f"Eastern: {eastern_time}")
print(f"Pacific: {pacific_time}")
# Create timezone-aware datetime directly
eastern_dt = eastern.localize(datetime.datetime(2023, 12, 7, 14, 30))
print(f"Eastern datetime: {eastern_dt}")
# Convert between timezones
pacific_dt = eastern_dt.astimezone(pacific)
print(f"Same time in Pacific: {pacific_dt}")Practical Examples
Age Calculator
import datetime
def calculate_age(birth_date):
"""Calculate age in years from birth date."""
today = datetime.date.today()
age = today.year - birth_date.year
# Check if birthday has occurred this year
if today < birth_date.replace(year=today.year):
age -= 1
return age
# Example usage
birth_date = datetime.date(1990, 5, 15)
age = calculate_age(birth_date)
print(f"Age: {age} years")
# Days until next birthday
def days_until_birthday(birth_date):
today = datetime.date.today()
next_birthday = birth_date.replace(year=today.year)
if next_birthday < today:
next_birthday = birth_date.replace(year=today.year + 1)
return (next_birthday - today).days
days = days_until_birthday(birth_date)
print(f"Days until next birthday: {days}")Business Days Calculator
import datetime
def add_business_days(start_date, business_days):
"""Add business days to a date (excluding weekends)."""
current_date = start_date
days_added = 0
while days_added < business_days:
current_date += datetime.timedelta(days=1)
# Monday is 0, Sunday is 6
if current_date.weekday() < 5: # Monday to Friday
days_added += 1
return current_date
def count_business_days(start_date, end_date):
"""Count business days between two dates."""
current_date = start_date
business_days = 0
while current_date <= end_date:
if current_date.weekday() < 5:
business_days += 1
current_date += datetime.timedelta(days=1)
return business_days
# Example usage
start = datetime.date(2023, 12, 1)
end_date = add_business_days(start, 10)
print(f"10 business days from {start}: {end_date}")
business_day_count = count_business_days(start, end_date)
print(f"Business days between dates: {business_day_count}")Event Scheduler
import datetime
class Event:
def __init__(self, name, start_time, duration_minutes):
self.name = name
self.start_time = start_time
self.duration = datetime.timedelta(minutes=duration_minutes)
self.end_time = start_time + self.duration
def __str__(self):
return f"{self.name}: {self.start_time.strftime('%Y-%m-%d %H:%M')} - {self.end_time.strftime('%H:%M')}"
def conflicts_with(self, other_event):
"""Check if this event conflicts with another event."""
return (self.start_time < other_event.end_time and
self.end_time > other_event.start_time)
def time_until_event(self):
"""Get time until event starts."""
now = datetime.datetime.now()
if now < self.start_time:
return self.start_time - now
return None
# Example usage
meeting1 = Event("Team Meeting",
datetime.datetime(2023, 12, 7, 14, 0), 60)
meeting2 = Event("Client Call",
datetime.datetime(2023, 12, 7, 14, 30), 30)
print(meeting1)
print(meeting2)
print(f"Conflicts: {meeting1.conflicts_with(meeting2)}")
time_until = meeting1.time_until_event()
if time_until:
print(f"Time until meeting: {time_until}")Formatting with strftime and strptime
strftime turns a date into a string; strptime parses a string into a date. The direction is easy to remember: f = format (out), p = parse (in).
from datetime import datetime
now = datetime(2026, 8, 18, 14, 30)
print(now.strftime("%Y-%m-%d")) # 2026-08-18
print(now.strftime("%d %b %Y")) # 18 Aug 2026
print(now.strftime("%H:%M")) # 14:30
parsed = datetime.strptime("2026-01-15", "%Y-%m-%d")
print(parsed.year) # 2026| Code | Means | Example |
|---|---|---|
%Y | 4-digit year | 2026 |
%m / %d | month / day | 08 / 18 |
%H:%M:%S | time | 14:30:00 |
%A / %b | weekday / month name | Tuesday / Aug |
Date Arithmetic with timedelta
from datetime import datetime, timedelta
today = datetime(2026, 8, 18)
print(today + timedelta(days=7)) # 2026-08-25
print(today - timedelta(weeks=2)) # 2026-08-04
due = datetime(2026, 12, 25)
print((due - today).days, "days to go") # 129 days to goFor time zones, use datetime.now(timezone.utc) and aware datetimes rather than naive ones — it prevents subtle bugs across regions.
Try It Yourself
Exercise 1: Print today's date in the format DD/MM/YYYY.
Show solution
from datetime import date
print(date.today().strftime("%d/%m/%Y"))Exercise 2: How many days are between 2026-01-01 and 2026-03-01?
Show solution
from datetime import date
print((date(2026, 3, 1) - date(2026, 1, 1)).days) # 59Key Takeaways
- Use the
datetimemodule for dates and times. strftimeformats out;strptimeparses in.timedeltadoes date arithmetic.- Prefer timezone-aware datetimes for real applications.
📘 Real-World Deep Dive
Dates seem easy but explode in production because of timezones, daylight-saving, and "is this a string or a datetime?". Using <code>datetime</code> + <code>pytz</code> (or <code>zoneinfo</code>) is the disciplined pattern.
Real-Life Scenario
A small billing/metering utility: parse "human" durations, bucket events into per-day windows, compute SLA breaches, and emit ISO-8601 wall-clock strings.
Real-Life Example
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo
def parse_utc(s: str) -> datetime:
return datetime.fromisoformat(s).replace(tzinfo=timezone.utc)
NY = ZoneInfo("America/New_York")
events = [
("login", "2026-08-19T22:00:00"),
("login", "2026-08-20T08:00:00"),
("order", "2026-08-20T09:15:00"),
("logout", "2026-08-20T17:30:00"),
]
utc = [parse_utc(t) for _, t in events]
local = [t.astimezone(NY) for t in utc]
day_buckets: dict[str, int] = {}
for t in utc:
day_buckets.setdefault(t.date().isoformat(), 0)
day_buckets[t.date().isoformat()] += 1
SLA = timedelta(hours=8)
breaches = [(kind, t, t + SLA) for kind, t in zip([k for k, _ in events], utc) if (datetime.now(timezone.utc) - t) > SLA]
print("per-day counts:", day_buckets)
print("local times :", [t.strftime("%Y-%m-%d %H:%M %Z") for t in local])
print("sla breaches :", [(kind, t.isoformat()) for kind, t, *_ in breaches])Expected Output
per-day counts: {'2026-08-19': 1, '2026-08-20': 3}
local times : ['2026-08-19 18:00 EDT', '2026-08-20 04:00 EDT', '2026-08-20 05:15 EDT', '2026-08-20 13:30 EDT']
sla breaches : []Common mistakes
- Naive datetimes are not comparable across processes — always store as UTC at the boundary.
datetime.utcnow()is deprecated — usedatetime.now(timezone.utc)instead.- Adding a
timedelta(days=1)across DST does not add an hour; wall-clock arithmetic is ambiguous.
🚀 Performance & Best Practices
- Build timestamps as integer epoch nanoseconds (the stdlib offers it via
datetime.timestamp()). - For huge time-series, use
numpy.datetime64orpandas.Timestamp; they vectorise. - Cache
ZoneInfoobjects — instantiation reads from disk.
🧪 Try It Yourself
- Add a CLI flag
--tz Europe/Londonto pick the wall-clock zone. - Compute business-day deltas using
pandas.bdate_range. - Plot the daily count in a Seaborn bar chart.