Module 18 - Dates & Time
Working with dates and times is essential in programming. Python's datetime module provides classes for manipulating dates, times, timezones, and time intervals.
1. The datetime Module
Core Classes
| Class | Description | Example |
|---|---|---|
datetime | Date and time combined | 2024-01-15 10:30:45 |
date | Date only (year, month, day) | 2024-01-15 |
time | Time only (hour, minute, second) | 10:30:45 |
timedelta | Duration/difference between times | 5 days, 3 hours |
timezone | Timezone information | UTC, EST |
import datetime
# Current date and time
now = datetime.datetime.now()
print(now) # 2024-01-15 10:30:45.123456
# Current date only
today = datetime.date.today()
print(today) # 2024-01-15
# Current time only
current_time = datetime.datetime.now().time()
print(current_time) # 10:30:45.123456
2. Creating Date and Time Objects
2.1 datetime Objects
from datetime import datetime
# Create specific datetime
dt = datetime(2024, 1, 15, 10, 30, 45)
print(dt) # 2024-01-15 10:30:45
# With microseconds
dt = datetime(2024, 1, 15, 10, 30, 45, 123456)
print(dt) # 2024-01-15 10:30:45.123456
# Current datetime
now = datetime.now()
print(now)
# UTC datetime
utc_now = datetime.utcnow()
print(utc_now)
2.2 date Objects
from datetime import date
# Create specific date
d = date(2024, 1, 15)
print(d) # 2024-01-15
# Current date
today = date.today()
print(today)
# Access components
print(today.year) # 2024
print(today.month) # 1
print(today.day) # 15
2.3 time Objects
from datetime import time
# Create specific time
t = time(14, 30, 45)
print(t) # 14:30:45
# With microseconds
t = time(14, 30, 45, 123456)
print(t) # 14:30:45.123456
# Access components
print(t.hour) # 14
print(t.minute) # 30
print(t.second) # 45
print(t.microsecond) # 123456
3. Formatting Dates and Times
3.1 strftime() - Date to String
from datetime import datetime
now = datetime.now()
# Common formats
print(now.strftime("%Y-%m-%d")) # 2024-01-15
print(now.strftime("%d/%m/%Y")) # 15/01/2024
print(now.strftime("%B %d, %Y")) # January 15, 2024
print(now.strftime("%I:%M %p")) # 10:30 AM
print(now.strftime("%A, %B %d, %Y")) # Monday, January 15, 2024
print(now.strftime("%Y-%m-%d %H:%M:%S")) # 2024-01-15 10:30:45
Format Codes
| Code | Meaning | Example |
|---|---|---|
%Y | Year (4 digits) | 2024 |
%y | Year (2 digits) | 24 |
%m | Month (01-12) | 01 |
%B | Month name (full) | January |
%b | Month name (abbr) | Jan |
%d | Day of month (01-31) | 15 |
%A | Weekday (full) | Monday |
%a | Weekday (abbr) | Mon |
%H | Hour (00-23) | 14 |
%I | Hour (01-12) | 02 |
%M | Minute (00-59) | 30 |
%S | Second (00-59) | 45 |
%p | AM/PM | PM |
3.2 strptime() - String to Date
from datetime import datetime
# Parse date strings
date_string = "2024-01-15"
dt = datetime.strptime(date_string, "%Y-%m-%d")
print(dt) # 2024-01-15 00:00:00
# Parse with time
date_string = "15/01/2024 14:30:45"
dt = datetime.strptime(date_string, "%d/%m/%Y %H:%M:%S")
print(dt) # 2024-01-15 14:30:45
# Parse various formats
formats = [
("January 15, 2024", "%B %d, %Y"),
("15-Jan-2024", "%d-%b-%Y"),
("01/15/2024", "%m/%d/%Y")
]
for date_str, fmt in formats:
dt = datetime.strptime(date_str, fmt)
print(f"{date_str} → {dt}")
4. timedelta - Time Differences
timedelta represents a duration or difference between two dates/times.
Creating timedelta
from datetime import timedelta
# Create durations
delta = timedelta(days=7)
print(delta) # 7 days, 0:00:00
delta = timedelta(hours=5, minutes=30)
print(delta) # 5:30:00
delta = timedelta(weeks=2, days=3, hours=4, minutes=30, seconds=15)
print(delta) # 17 days, 4:30:15
Arithmetic with Dates
from datetime import datetime, timedelta
now = datetime.now()
# Add time
future = now + timedelta(days=7)
print(f"One week from now: {future}")
past = now - timedelta(days=30)
print(f"30 days ago: {past}")
# Subtract dates
date1 = datetime(2024, 1, 15)
date2 = datetime(2024, 1, 1)
difference = date1 - date2
print(f"Difference: {difference.days} days") # 14 days
# Calculate age
birthday = datetime(1990, 5, 15)
age = datetime.now() - birthday
age_years = age.days // 365
print(f"Age: {age_years} years")
Practical Examples
from datetime import datetime, timedelta
# Calculate deadlines
project_start = datetime(2024, 1, 15)
duration = timedelta(weeks=8)
deadline = project_start + duration
print(f"Project deadline: {deadline.strftime('%B %d, %Y')}")
# Business days calculation
def add_business_days(start_date, days):
"""Add business days (skip weekends)"""
current = start_date
while days > 0:
current += timedelta(days=1)
if current.weekday() < 5: # Monday=0, Sunday=6
days -= 1
return current
start = datetime(2024, 1, 15) # Monday
result = add_business_days(start, 10)
print(f"10 business days from {start.date()}: {result.date()}")
5. Working with Weekdays
from datetime import datetime, date
today = date.today()
# Get weekday
weekday = today.weekday() # Monday=0, Sunday=6
print(f"Weekday number: {weekday}")
# Get weekday name
weekday_name = today.strftime("%A")
print(f"Today is {weekday_name}")
# Check if weekend
if today.weekday() >= 5:
print("It's the weekend!")
else:
print("It's a weekday")
# Find next Monday
days_until_monday = (7 - today.weekday()) % 7
if days_until_monday == 0:
days_until_monday = 7
next_monday = today + timedelta(days=days_until_monday)
print(f"Next Monday: {next_monday}")
6. Timezones
Using timezone and tzinfo
from datetime import datetime, timezone, timedelta
# UTC timezone
utc = timezone.utc
now_utc = datetime.now(utc)
print(now_utc)
# Custom timezone (EST = UTC-5)
est = timezone(timedelta(hours=-5))
now_est = datetime.now(est)
print(now_est)
# Convert between timezones
utc_time = datetime.now(timezone.utc)
est_time = utc_time.astimezone(timezone(timedelta(hours=-5)))
print(f"UTC: {utc_time}")
print(f"EST: {est_time}")
Using pytz (Recommended for Complex Timezones)
# Install: pip install pytz
import pytz
from datetime import datetime
# List all timezones
# print(pytz.all_timezones)
# Create timezone-aware datetime
utc = pytz.UTC
eastern = pytz.timezone('America/New_York')
tokyo = pytz.timezone('Asia/Tokyo')
# Current time in different zones
now_utc = datetime.now(utc)
now_eastern = now_utc.astimezone(eastern)
now_tokyo = now_utc.astimezone(tokyo)
print(f"UTC: {now_utc}")
print(f"New York: {now_eastern}")
print(f"Tokyo: {now_tokyo}")
# Localize naive datetime
naive = datetime(2024, 1, 15, 10, 30)
localized = eastern.localize(naive)
print(localized)
7. Practical Examples
7.1 Age Calculator
from datetime import datetime
def calculate_age(birthdate):
"""Calculate age in years"""
today = datetime.now().date()
age = today.year - birthdate.year
# Adjust if birthday hasn't occurred this year
if today.month < birthdate.month or \
(today.month == birthdate.month and today.day < birthdate.day):
age -= 1
return age
birthday = datetime(1990, 5, 15).date()
age = calculate_age(birthday)
print(f"Age: {age} years")
7.2 Countdown Timer
from datetime import datetime
def countdown_to_event(event_date):
"""Calculate time until event"""
now = datetime.now()
delta = event_date - now
if delta.total_seconds() < 0:
return "Event has passed!"
days = delta.days
hours, remainder = divmod(delta.seconds, 3600)
minutes, seconds = divmod(remainder, 60)
return f"{days} days, {hours} hours, {minutes} minutes, {seconds} seconds"
# New Year 2025
new_year = datetime(2025, 1, 1, 0, 0, 0)
print(f"Time until New Year: {countdown_to_event(new_year)}")
7.3 Date Range Generator
from datetime import datetime, timedelta
def date_range(start, end, step=1):
"""Generate dates between start and end"""
current = start
while current <= end:
yield current
current += timedelta(days=step)
# Generate all Mondays in January 2024
start = datetime(2024, 1, 1)
end = datetime(2024, 1, 31)
for date in date_range(start, end):
if date.weekday() == 0: # Monday
print(date.strftime("%A, %B %d"))
7.4 Working Hours Calculator
from datetime import datetime, time
def is_working_hours(dt, start_hour=9, end_hour=17):
"""Check if datetime is during working hours"""
if dt.weekday() >= 5: # Weekend
return False
work_start = time(start_hour, 0)
work_end = time(end_hour, 0)
return work_start <= dt.time() <= work_end
# Test
test_times = [
datetime(2024, 1, 15, 10, 30), # Monday 10:30 AM
datetime(2024, 1, 15, 19, 0), # Monday 7:00 PM
datetime(2024, 1, 20, 10, 30), # Saturday 10:30 AM
]
for dt in test_times:
status = "Working hours" if is_working_hours(dt) else "Outside working hours"
print(f"{dt.strftime('%A %I:%M %p')}: {status}")
8. Performance and Best Practices
Comparing Dates
from datetime import datetime
date1 = datetime(2024, 1, 15)
date2 = datetime(2024, 1, 20)
# Comparison operators
print(date1 < date2) # True
print(date1 == date2) # False
print(date1 != date2) # True
# Get maximum/minimum
dates = [datetime(2024, 1, 15), datetime(2024, 1, 10), datetime(2024, 1, 20)]
print(f"Earliest: {min(dates)}")
print(f"Latest: {max(dates)}")
Unix Timestamp
from datetime import datetime
# Current timestamp
timestamp = datetime.now().timestamp()
print(f"Timestamp: {timestamp}")
# Convert timestamp to datetime
dt = datetime.fromtimestamp(timestamp)
print(f"Datetime: {dt}")
# UTC timestamp
dt_utc = datetime.utcfromtimestamp(timestamp)
print(f"UTC: {dt_utc}")
Best Practices
- Always use timezone-aware datetimes for production applications
- Store UTC in databases, convert to local timezone for display
- Use
date.today()for current date, notdatetime.now().date() - Validate date inputs to prevent invalid dates
9. Common Pitfalls
from datetime import datetime, timedelta
# ❌ Incorrect: Comparing naive and aware datetimes
naive = datetime(2024, 1, 15)
aware = datetime.now(timezone.utc)
# This raises TypeError!
# print(naive < aware)
# ✅ Correct: Both naive or both aware
naive1 = datetime(2024, 1, 15)
naive2 = datetime(2024, 1, 20)
print(naive1 < naive2) # OK
# ❌ Incorrect: Assuming 30 days per month
# Wrong for February, months with 31 days
future = datetime.now() + timedelta(days=30)
# ✅ Correct: Use dateutil.relativedelta for months
from dateutil.relativedelta import relativedelta
future = datetime.now() + relativedelta(months=1)
Summary
✅ datetime module handles dates, times, and durations
✅ Use strftime() to format dates, strptime() to parse
✅ timedelta represents time differences
✅ Always use timezone-aware datetimes in production
✅ pytz library for comprehensive timezone support
✅ Store UTC in databases, display in local time
Next Steps
In Module 19, you'll learn:
- JSON serialization and deserialization
- Working with the
jsonmodule picklefor Python object serialization- Data persistence techniques
Practice Exercises
- Create a function that calculates the number of days until your next birthday
- Build a date formatter that converts between different date formats
- Write a function to find all Fridays in a given year
- Create a timezone converter between major world cities
- Build a simple reminder system that checks if an event is due
Challenge
Create a meeting scheduler that:
- Takes meeting duration and preferred time
- Checks availability across multiple timezones
- Suggests next available slot during business hours (9 AM - 5 PM)
- Accounts for weekends and holidays
- Returns meeting time in all participant timezones