Working with Dates and Times in Python
A comprehensive guide to Python date and time handling, including formatting dates, date calculations, timezone handling, and troubleshooting common issues. This guide covers everything from basic date creation to advanced business date calculations.
Quick Start / TL;DR
- Basic imports:
from datetime import datetime, date, timedelta - Create current date:
datetime.now()ordate.today() - Parse date string:
datetime.strptime("2023-12-25", "%Y-%m-%d") - Format for display:
dt.strftime("%B %d, %Y")# December 25, 2023 - Date arithmetic:
dt + timedelta(days=7)# Add 7 days - Timezone-aware: Use
zoneinfofor proper timezone handling
Common Questions
How do I work with dates and times in Python?
Python provides several built-in modules for date and time handling:
from datetime import datetime, date, time, timedelta
from zoneinfo import ZoneInfo
# Current date and time
now = datetime.now()
today = date.today()
current_time = time(14, 30, 0) # 2:30 PM
print(f"Now: {now}")
print(f"Today: {today}")
print(f"Time: {current_time}")
Output:
Now: 2025-09-19 14:30:45.123456
Today: 2025-09-19
Time: 14:30:00
What's the difference between datetime, date, and time objects?
Here's a comparison of Python's core date/time types:
| Type | Purpose | Example | Use Case |
|---|---|---|---|
datetime |
Full date + time | 2025-09-19 14:30:45 |
Timestamps, logging, precise scheduling |
date |
Date only | 2025-09-19 |
Birthdays, deadlines, calendar events |
time |
Time only | 14:30:45 |
Daily schedules, recurring times |
timedelta |
Duration/difference | 7 days, 2:30:45 |
Date arithmetic, intervals |
Examples of each type
from datetime import datetime, date, time, timedelta
dt = datetime(2025, 9, 19, 14, 30, 45) # Full datetime
d = date(2025, 9, 19) # Date only
t = time(14, 30, 45) # Time only
td = timedelta(days=7, hours=2) # Duration
print(f"DateTime: {dt}")
print(f"Date: {d}")
print(f"Time: {t}")
print(f"TimeDelta: {td}")
# Convert between types
date_from_datetime = dt.date() # Extract date
time_from_datetime = dt.time() # Extract time
datetime_from_parts = datetime.combine(d, t) # Combine date + time
Output:
DateTime: 2025-09-19 14:30:45
Date: 2025-09-19
Time: 14:30:45
TimeDelta: 7 days, 2:00:00
How do I parse date strings in Python?
For known formats, use strptime(), which takes two arguments: the date string and a format string describing its structure (using special codes like %Y for year, %m for month, %d for day, etc). This lets you precisely parse dates when you know their exact format:
from datetime import datetime
# Examples using known formats
dt = datetime.strptime("2025-09-19", "%Y-%m-%d")
dt = datetime.strptime("09/19/2025", "%m/%d/%Y")
dt = datetime.strptime("Sep 19, 2025", "%b %d, %Y")
dt = datetime.strptime("September 19, 2025", "%B %d, %Y")
dt = datetime.strptime("2025-09-19 14:30:45", "%Y-%m-%d %H:%M:%S")
For unknown formats, use the dateutil library:
import dateutil.parser as parser
# These all work without specifying format
date_strings = [
"October 11, 2025",
"Oct 11, 2025",
"Oct 11th, 2025",
"2025-10-11T14:30:00",
"next tuesday",
"tomorrow at 3pm"
]
for date_string in date_strings:
try:
parsed_date = parser.parse(date_string)
print(f"'{date_string}' → {parsed_date}")
except parser.ParserError as e:
print(f"Could not parse '{date_string}': {e}")
How do I format dates for display?
Use strftime() for custom formatting:
from datetime import datetime
dt = datetime(2025, 9, 19, 14, 30, 45)
# Common display formats
formats = {
"ISO format": dt.strftime("%Y-%m-%d"),
"US format": dt.strftime("%m/%d/%Y"),
"Long format": dt.strftime("%B %d, %Y"),
"Short format": dt.strftime("%b %d, %Y"),
"With time": dt.strftime("%Y-%m-%d %H:%M:%S"),
"12-hour time": dt.strftime("%Y-%m-%d %I:%M:%S %p"),
"Weekday": dt.strftime("%A, %B %d, %Y"),
"RFC format": dt.strftime("%a, %d %b %Y %H:%M:%S"),
}
for name, formatted in formats.items():
print(f"{name:12}: {formatted}")
Output:
ISO format : 2025-09-19
US format : 09/19/2025
Long format : September 19, 2025
Short format: Sep 19, 2025
With time : 2025-09-19 14:30:45
12-hour time: 2025-09-19 02:30:45 PM
Weekday : Friday, September 19, 2025
RFC format : Fri, 19 Sep 2025 14:30:45
How do I calculate the difference between two dates?
Use date arithmetic to get timedelta objects:
from datetime import datetime, date, timedelta
# Calculate age
birth_date = date(1990, 5, 15)
today = date.today()
age_delta = today - birth_date
print(f"Age: {age_delta.days} days")
print(f"Age in years: {age_delta.days // 365.25:.1f} years")
# Project deadlines
project_start = datetime(2025, 9, 1, 9, 0)
project_end = datetime(2025, 12, 15, 17, 0)
project_duration = project_end - project_start
print(f"Project duration: {project_duration}")
print(f"Working days: {project_duration.days}")
print(f"Total hours: {project_duration.total_seconds() / 3600:.0f} hours")
# Business days calculation (excluding weekends)
def business_days_between(start_date, end_date):
"""Calculate business days between two dates."""
current = start_date
business_days = 0
while current <= end_date:
if current.weekday() < 5: # Monday=0, Sunday=6
business_days += 1
current += timedelta(days=1)
return business_days
start = date(2025, 9, 15) # Monday
end = date(2025, 9, 26) # Friday
biz_days = business_days_between(start, end)
print(f"Business days: {biz_days}")
What are timezone-aware vs naive datetimes?
Naive datetimes have no timezone information:
from datetime import datetime
# Naive datetime - no timezone info
naive_dt = datetime(2025, 9, 19, 14, 30)
print(f"Naive: {naive_dt} (tzinfo: {naive_dt.tzinfo})")
Timezone-aware datetimes include timezone information:
from datetime import datetime, timezone
from zoneinfo import ZoneInfo # Python 3.9+
# UTC timezone
utc_dt = datetime(2025, 9, 19, 14, 30, tzinfo=timezone.utc)
print(f"UTC: {utc_dt}")
# Specific timezones using zoneinfo
ny_dt = datetime(2025, 9, 19, 14, 30, tzinfo=ZoneInfo("America/New_York"))
tokyo_dt = datetime(2025, 9, 19, 14, 30, tzinfo=ZoneInfo("Asia/Tokyo"))
print(f"New York: {ny_dt}")
print(f"Tokyo: {tokyo_dt}")
# Convert between timezones
ny_time = utc_dt.astimezone(ZoneInfo("America/New_York"))
print(f"UTC {utc_dt.time()} → NY {ny_time.time()}")
# Current time in different timezones
now_utc = datetime.now(timezone.utc)
now_ny = now_utc.astimezone(ZoneInfo("America/New_York"))
now_tokyo = now_utc.astimezone(ZoneInfo("Asia/Tokyo"))
print(f"UTC: {now_utc.strftime('%H:%M')}")
print(f"NY: {now_ny.strftime('%H:%M')}")
print(f"Tokyo: {now_tokyo.strftime('%H:%M')}")
Creating Date Objects
First off, all basic examples use the following import, any additional imports needed will be shown with the example.
from datetime import datetime
How do I create a specific date?
from datetime import datetime, date, time
# Current date/time
now = datetime.now()
today = date.today()
# Specific dates - multiple ways
dt1 = datetime(2025, 8, 28)
dt2 = datetime(year=2025, month=3, day=2)
dt3 = datetime(2025, 8, 28, 14, 30, 45) # With time
# Date only
date1 = date(2025, 8, 28)
# Time only
time1 = time(14, 30, 45)
print(f"Now: {now}")
print(f"Today: {today}")
print(f"Specific datetime: {dt3}")
print(f"Date only: {date1}")
print(f"Time only: {time1}")
How do I create a date from a timestamp?
Create a Python date object from a unix timestamp (seconds since epoch):
import time as time_module
# Current timestamp
current_timestamp = time_module.time()
print(f"Current timestamp: {current_timestamp}")
# Specific timestamp
timestamp = 1294204471
dt = datetime.fromtimestamp(timestamp)
print(f"Timestamp {timestamp} → {dt}")
# Timezone-aware from timestamp
utc_dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
print(f"UTC: {utc_dt}")
# Convert datetime back to timestamp
back_to_timestamp = dt.timestamp()
print(f"Back to timestamp: {back_to_timestamp}")
Date Format Reference Table
Printing dates in various formats is straightforward using strftime(). Here's the complete reference:
dt = datetime(2025, 8, 22, 14, 30, 45, 123456)
print(f"Example date: {dt}")
print(f"Formatted: {dt.strftime('%b %d, %Y at %I:%M %p')}")
# Output: Aug 22, 2025 at 02:30 PM
| Symbol | Definition | Example | Usage |
|---|---|---|---|
| Date Components | |||
| %Y | Year with century | 2025 | Full year |
| %y | Year without century | 25 | Two-digit year |
| %m | Month as number | 08 | Numeric month [01-12] |
| %B | Full month name | August | Full month name |
| %b | Abbreviated month | Aug | Short month name |
| %d | Day of month | 22 | Day [01-31] |
| Time Components | |||
| %H | Hour (24-hour) | 14 | Military time [00-23] |
| %I | Hour (12-hour) | 02 | Standard time [01-12] |
| %M | Minute | 30 | Minutes [00-59] |
| %S | Second | 45 | Seconds [00-59] |
| %f | Microsecond | 123456 | Microseconds [000000-999999] |
| %p | AM/PM | PM | Locale's AM/PM |
| Weekday Components | |||
| %A | Full weekday name | Friday | Full day name |
| %a | Abbreviated weekday | Fri | Short day name |
| %w | Weekday as number | 5 | Sunday=0 to Saturday=6 |
| Week/Year Components | |||
| %j | Day of year | 234 | Julian day [001-366] |
| %U | Week number (Sunday first) | 33 | Week of year [00-53] |
| %W | Week number (Monday first) | 33 | Week of year [00-53] |
| Timezone Components | |||
| %z | UTC offset | +0000 | ±HHMM or empty |
| %Z | Timezone name | UTC | Time zone name |
| Locale Components | |||
| %c | Complete date/time | Fri Aug 22 14:30:45 2025 | Locale's datetime |
| %x | Locale date | 08/22/25 | Locale's date |
| %X | Locale time | 14:30:45 | Locale's time |
| Literal | |||
| %% | Literal % | % | Percent character |
Common Format Examples
dt = datetime(2025, 8, 22, 14, 30, 45)
common_formats = {
"ISO 8601": dt.strftime("%Y-%m-%d"), # 2025-08-22
"US Date": dt.strftime("%m/%d/%Y"), # 08/22/2025
"European": dt.strftime("%d/%m/%Y"), # 22/08/2025
"Long Format": dt.strftime("%B %d, %Y"), # August 22, 2025
"With Weekday": dt.strftime("%A, %B %d, %Y"), # Friday, August 22, 2025
"Short": dt.strftime("%b %d"), # Aug 22
"Time 24h": dt.strftime("%H:%M:%S"), # 14:30:45
"Time 12h": dt.strftime("%I:%M:%S %p"), # 02:30:45 PM
"DateTime": dt.strftime("%Y-%m-%d %H:%M:%S"), # 2025-08-22 14:30:45
"RFC 2822": dt.strftime("%a, %d %b %Y %H:%M:%S"), # Fri, 22 Aug 2025 14:30:45
"Log Format": dt.strftime("[%Y-%m-%d %H:%M:%S]"), # [2025-08-22 14:30:45]
}
for name, formatted in common_formats.items():
print(f"{name:12}: {formatted}")
How do I format dates for specific standards?
RFC 2822 Format (Email Headers)
Use the formatdate() function from the email.utils built-in module.
For the current date and time:
from email.utils import formatdate
current_rfc = formatdate()
print(f"Current RFC 2822: {current_rfc}")
# Output: 'Thu, 19 Sep 2025 14:30:44 +0000'
If you need a specific date to format, pass in a unix timestamp:
from email.utils import formatdate
from datetime import datetime
dt = datetime(2025, 1, 25, 12, 0, 0)
rfc_formatted = formatdate(dt.timestamp())
print(f"Specific RFC 2822: {rfc_formatted}")
# Output: 'Sat, 25 Jan 2025 12:00:00 +0000'
ISO 8601 Format
from datetime import datetime, timezone
dt = datetime(2025, 9, 19, 14, 30, 45, 123456)
# Various ISO formats
iso_formats = {
"Date only": dt.date().isoformat(), # 2025-09-19
"DateTime": dt.isoformat(), # 2025-09-19T14:30:45.123456
"DateTime (no microseconds)": dt.replace(microsecond=0).isoformat(), # 2025-09-19T14:30:45
"With timezone": dt.replace(tzinfo=timezone.utc).isoformat(), # 2025-09-19T14:30:45.123456+00:00
}
for name, formatted in iso_formats.items():
print(f"{name:25}: {formatted}")
Date Calculations and Timedelta
How do I add or subtract time from dates?
Use timedelta for date arithmetic:
from datetime import datetime, timedelta
dt = datetime(2025, 9, 19, 14, 30, 45)
# Adding time
future_dates = {
"1 week later": dt + timedelta(weeks=1),
"7 days later": dt + timedelta(days=7),
"5 hours later": dt + timedelta(hours=5),
"30 minutes later": dt + timedelta(minutes=30),
"45 seconds later": dt + timedelta(seconds=45),
"1000 microseconds later": dt + timedelta(microseconds=1000),
}
# Subtracting time
past_dates = {
"1 week ago": dt - timedelta(weeks=1),
"7 days ago": dt - timedelta(days=7),
"5 hours ago": dt - timedelta(hours=5),
}
print(f"Base date: {dt}")
print("\nFuture dates:")
for description, future_dt in future_dates.items():
print(f" {description:20}: {future_dt}")
print("\nPast dates:")
for description, past_dt in past_dates.items():
print(f" {description:20}: {past_dt}")
Valid timedelta properties are:
weeks, days, hours, minutes, seconds, microseconds, milliseconds
Why should I avoid using days=365 for year calculations?
Don't be tempted to use days=365 for year calculations—this would be incorrect for leap years. Instead, use proper date construction:
from datetime import datetime, timedelta
# ❌ WRONG - doesn't account for leap years
start_date = datetime(2024, 2, 29) # Leap year date
wrong_next_year = start_date + timedelta(days=365)
print(f"Wrong approach: {wrong_next_year}") # 2025-02-28
# ✅ CORRECT - handles leap years properly
correct_next_year = datetime(year=start_date.year + 1,
month=start_date.month,
day=start_date.day)
print(f"Correct approach: {correct_next_year}") # 2025-02-28
# ✅ BETTER - handle leap year edge case
def add_years(dt, years):
"""Add years to a datetime, handling leap year edge cases."""
try:
return dt.replace(year=dt.year + years)
except ValueError:
# Handle Feb 29 on non-leap year
return dt.replace(year=dt.year + years, day=28)
leap_day = datetime(2024, 2, 29)
next_year = add_years(leap_day, 1)
print(f"Leap year handling: {next_year}") # 2025-02-28
How do I calculate the difference between two dates?
When you subtract date objects, they return timedelta objects:
from datetime import datetime, date
# DateTime calculations
dt1 = datetime(2025, 8, 23, 9, 30)
dt2 = datetime(2025, 8, 28, 17, 45)
time_diff = dt2 - dt1
print(f"Difference: {time_diff}")
print(f"Days: {time_diff.days}")
print(f"Seconds: {time_diff.seconds}")
print(f"Total seconds: {time_diff.total_seconds()}")
print(f"Total hours: {time_diff.total_seconds() / 3600:.1f}")
# Date-only calculations
date1 = date(2025, 1, 1)
date2 = date(2025, 12, 31)
date_diff = date2 - date1
print(f"Days in 2025: {date_diff.days}")
# Age calculation
birth_date = date(1990, 5, 15)
today = date.today()
age = today - birth_date
age_years = age.days / 365.25 # Account for leap years
print(f"Age: {age_years:.1f} years")
Output:
Difference: 5 days, 8:15:00
Days: 5
Seconds: 29700
Total seconds: 461700.0
Total hours: 128.2
Days in 2025: 364
Age: 35.4 years
Converting Between Date Types
How do I convert datetime to date?
To simplify a datetime to just the date, use the .date() method:
from datetime import datetime
dt = datetime.now()
print(f"DateTime: {dt}")
print(f"Date only: {dt.date()}")
print(f"Time only: {dt.time()}")
# Practical example: group events by date
events = [
datetime(2025, 9, 19, 9, 30),
datetime(2025, 9, 19, 14, 15),
datetime(2025, 9, 20, 10, 0),
]
events_by_date = {}
for event in events:
event_date = event.date()
if event_date not in events_by_date:
events_by_date[event_date] = []
events_by_date[event_date].append(event.time())
for date, times in events_by_date.items():
print(f"{date}: {times}")
How do I convert date to datetime?
To add a time to a date, use datetime.combine() to merge a date object with a time object:
from datetime import date, datetime, time
# Combine date and time
today = date.today()
morning_time = time(9, 0, 0)
afternoon_time = time(17, 30, 0)
morning_datetime = datetime.combine(today, morning_time)
afternoon_datetime = datetime.combine(today, afternoon_time)
print(f"Morning meeting: {morning_datetime}")
print(f"End of day: {afternoon_datetime}")
# Common use case: create datetime for start/end of day
def start_of_day(date_obj):
"""Get datetime for start of day (00:00:00)."""
return datetime.combine(date_obj, time.min)
def end_of_day(date_obj):
"""Get datetime for end of day (23:59:59.999999)."""
return datetime.combine(date_obj, time.max)
today = date.today()
print(f"Day starts: {start_of_day(today)}")
print(f"Day ends: {end_of_day(today)}")
Common Date Functions and Use Cases
Here are examples of commonly needed Python date functions with real-world applications.
How do I get yesterday's date?
from datetime import date, datetime, timedelta
# Yesterday as date
yesterday_date = date.today() - timedelta(days=1)
print(f"Yesterday: {yesterday_date.strftime('%Y-%m-%d')}")
# Yesterday as datetime
yesterday_datetime = datetime.now() - timedelta(days=1)
print(f"Yesterday (exact time): {yesterday_datetime}")
# Practical example: log file names
log_filename = f"app_{yesterday_date.strftime('%Y%m%d')}.log"
print(f"Yesterday's log file: {log_filename}")
How do I find the last day of the month?
Two reliable solutions:
Method 1: Using next month minus a day
from datetime import datetime, timedelta
def last_day_of_month_method1(dt):
"""Find last day of month by going to first day of next month."""
if dt.month == 12:
next_month = datetime(year=dt.year + 1, month=1, day=1)
else:
next_month = datetime(year=dt.year, month=dt.month + 1, day=1)
return next_month - timedelta(days=1)
now = datetime.now()
last_day = last_day_of_month_method1(now)
print(f"Last day of {now.strftime('%B')}: {last_day.date()}")
Method 2: Using the calendar module
import calendar
from datetime import datetime
def last_day_of_month_method2(dt):
"""Find last day of month using calendar module."""
_, last_day_num = calendar.monthrange(dt.year, dt.month)
return dt.replace(day=last_day_num)
now = datetime.now()
last_day = last_day_of_month_method2(now)
print(f"Last day of month: {last_day.date()}")
# Check if it's a leap year
def is_leap_year(year):
return calendar.isleap(year)
print(f"Is 2025 a leap year? {is_leap_year(2025)}")
print(f"Days in February 2025: {calendar.monthrange(2025, 2)[1]}")
How do I find the next occurrence of a specific weekday?
from datetime import datetime, timedelta
def next_weekday(weekday):
"""
Find the next occurrence of a specific weekday.
weekday: 0=Monday, 1=Tuesday, ..., 6=Sunday
"""
today = datetime.now()
days_ahead = weekday - today.weekday()
if days_ahead <= 0: # Target day already happened this week
days_ahead += 7
return today + timedelta(days=days_ahead)
# Find next Thursday (weekday 3)
next_thursday = next_weekday(3)
print(f"Next Thursday: {next_thursday.strftime('%A, %B %d, %Y')}")
# More readable version with names
weekday_names = {
'monday': 0, 'tuesday': 1, 'wednesday': 2, 'thursday': 3,
'friday': 4, 'saturday': 5, 'sunday': 6
}
def next_named_weekday(day_name):
"""Find next occurrence of named weekday."""
return next_weekday(weekday_names[day_name.lower()])
next_friday = next_named_weekday('friday')
print(f"Next Friday: {next_friday.strftime('%A, %B %d, %Y')}")
How do I find the first Monday of the month?
from datetime import datetime, timedelta
def first_monday_of_month(year, month):
"""Find the first Monday of a specific month."""
# First day of the month
first_day = datetime(year, month, 1)
# Find how many days until Monday (0 = Monday)
days_until_monday = (7 - first_day.weekday()) % 7
if days_until_monday == 0 and first_day.weekday() != 0:
days_until_monday = 7
first_monday = first_day + timedelta(days=days_until_monday)
return first_monday
# Current month's first Monday
today = datetime.now()
first_monday = first_monday_of_month(today.year, today.month)
print(f"First Monday of {today.strftime('%B')}: {first_monday.date()}")
# More general solution for any weekday
def first_weekday_of_month(year, month, weekday):
"""
Find the first occurrence of a weekday in a month.
weekday: 0=Monday, 1=Tuesday, ..., 6=Sunday
"""
first_day = datetime(year, month, 1)
first_weekday_day = first_day.weekday()
days_to_add = (weekday - first_weekday_day) % 7
return first_day + timedelta(days=days_to_add)
# Examples
first_wednesday = first_weekday_of_month(2025, 9, 2) # Wednesday
print(f"First Wednesday of September 2025: {first_wednesday.date()}")
How do I work with business days and holidays?
from datetime import date, timedelta
def is_weekend(dt):
"""Check if date falls on weekend."""
return dt.weekday() >= 5 # Saturday=5, Sunday=6
def add_business_days(start_date, business_days):
"""Add business days to a date, skipping weekends."""
current_date = start_date
days_added = 0
while days_added < business_days:
current_date += timedelta(days=1)
if not is_weekend(current_date):
days_added += 1
return current_date
def business_days_between(start_date, end_date):
"""Count business days between two dates."""
current = start_date
business_days = 0
while current <= end_date:
if not is_weekend(current):
business_days += 1
current += timedelta(days=1)
return business_days
# Examples
today = date.today()
five_biz_days_later = add_business_days(today, 5)
print(f"5 business days from {today}: {five_biz_days_later}")
# Count business days in a period
start = date(2025, 9, 1) # Monday
end = date(2025, 9, 30) # Tuesday
biz_days = business_days_between(start, end)
print(f"Business days in September 2025: {biz_days}")
# Simple holiday handling
US_HOLIDAYS_2025 = [
date(2025, 1, 1), # New Year's Day
date(2025, 7, 4), # Independence Day
date(2025, 12, 25), # Christmas Day
]
def is_holiday(dt, holidays=US_HOLIDAYS_2025):
"""Check if date is a holiday."""
return dt in holidays
def is_business_day(dt):
"""Check if date is a business day (not weekend or holiday)."""
return not is_weekend(dt) and not is_holiday(dt)
test_date = date(2025, 7, 4) # July 4th, 2025 (Friday)
print(f"Is {test_date} a business day? {is_business_day(test_date)}")
Advanced Date and Time Operations
How do I handle timezone conversions?
Using zoneinfo:
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
# Create timezone-aware datetimes
utc_now = datetime.now(timezone.utc)
ny_time = datetime.now(ZoneInfo("America/New_York"))
london_time = datetime.now(ZoneInfo("Europe/London"))
tokyo_time = datetime.now(ZoneInfo("Asia/Tokyo"))
print(f"UTC: {utc_now.strftime('%Y-%m-%d %H:%M:%S %Z')}")
print(f"New York: {ny_time.strftime('%Y-%m-%d %H:%M:%S %Z')}")
print(f"London: {london_time.strftime('%Y-%m-%d %H:%M:%S %Z')}")
print(f"Tokyo: {tokyo_time.strftime('%Y-%m-%d %H:%M:%S %Z')}")
# Convert between timezones
meeting_utc = datetime(2025, 9, 19, 15, 0, tzinfo=timezone.utc)
meeting_ny = meeting_utc.astimezone(ZoneInfo("America/New_York"))
meeting_tokyo = meeting_utc.astimezone(ZoneInfo("Asia/Tokyo"))
print(f"Meeting times:")
print(f" UTC: {meeting_utc.strftime('%H:%M')}")
print(f" New York: {meeting_ny.strftime('%H:%M')}")
print(f" Tokyo: {meeting_tokyo.strftime('%H:%M')}")
How do I work with date ranges and iterations?
from datetime import date, datetime, timedelta
def date_range(start_date, end_date, step_days=1):
"""Generate dates between start and end date."""
current = start_date
while current <= end_date:
yield current
current += timedelta(days=step_days)
# Example: All dates in September 2025
start = date(2025, 9, 1)
end = date(2025, 9, 30)
print("All Mondays in September 2025:")
for dt in date_range(start, end):
if dt.weekday() == 0: # Monday
print(f" {dt.strftime('%A, %B %d')}")
# Weekly iterations
print("\nEvery week in September:")
for dt in date_range(start, end, 7):
print(f" Week starting: {dt}")
# Business days only
def business_date_range(start_date, end_date):
"""Generate only business days (Mon-Fri) between dates."""
for dt in date_range(start_date, end_date):
if dt.weekday() < 5: # Monday=0 to Friday=4
yield dt
print("\nFirst 5 business days in September:")
for i, dt in enumerate(business_date_range(start, end)):
if i >= 5:
break
print(f" {dt.strftime('%A, %B %d')}")
Troubleshooting Common Date/Time Issues
What are the most common datetime parsing errors?
1. Format Mismatch Errors:
from datetime import datetime
# ❌ Common mistake: wrong format string
try:
# This will fail - format doesn't match
dt = datetime.strptime("2025-09-19", "%m/%d/%Y")
except ValueError as e:
print(f"Format mismatch error: {e}")
# ✅ Correct approach: match format to string
dt = datetime.strptime("2025-09-19", "%Y-%m-%d")
print(f"Correctly parsed: {dt}")
# ✅ Better: Handle multiple formats
def safe_parse_date(date_string):
formats = ["%Y-%m-%d", "%m/%d/%Y", "%d/%m/%Y", "%B %d, %Y"]
for fmt in formats:
try:
return datetime.strptime(date_string, fmt)
except ValueError:
continue
raise ValueError(f"No matching format found for: {date_string}")
# Test with different formats
test_dates = ["2025-09-19", "09/19/2025", "September 19, 2025"]
for date_str in test_dates:
parsed = safe_parse_date(date_str)
print(f"'{date_str}' → {parsed}")
2. Timezone-Related Errors:
from datetime import datetime, timezone
# ❌ Mixing naive and timezone-aware datetimes
naive_dt = datetime(2025, 9, 19, 14, 30)
aware_dt = datetime(2025, 9, 19, 14, 30, tzinfo=timezone.utc)
try:
# This will raise TypeError
difference = aware_dt - naive_dt
except TypeError as e:
print(f"Timezone error: {e}")
# ✅ Convert naive to aware before operations
naive_as_utc = naive_dt.replace(tzinfo=timezone.utc)
difference = aware_dt - naive_as_utc
print(f"Time difference: {difference}")
# ✅ Better: Always use timezone-aware datetimes
def now_utc():
return datetime.now(timezone.utc)
def make_aware(dt, tz=timezone.utc):
"""Convert naive datetime to timezone-aware."""
if dt.tzinfo is None:
return dt.replace(tzinfo=tz)
return dt
3. Leap Year and Month-End Issues:
from datetime import datetime, timedelta
import calendar
def safe_add_months(dt, months):
"""Safely add months, handling month-end edge cases."""
target_month = dt.month + months
target_year = dt.year + (target_month - 1) // 12
target_month = ((target_month - 1) % 12) + 1
# Handle day overflow (e.g., Jan 31 + 1 month)
max_day = calendar.monthrange(target_year, target_month)[1]
target_day = min(dt.day, max_day)
return dt.replace(year=target_year, month=target_month, day=target_day)
# Examples of edge cases
edge_cases = [
datetime(2025, 1, 31), # Jan 31 + 1 month = Feb 28
datetime(2024, 2, 29), # Leap day + 1 year = Feb 28
datetime(2025, 8, 31), # Aug 31 + 1 month = Sep 30
]
for dt in edge_cases:
next_month = safe_add_months(dt, 1)
print(f"{dt.date()} + 1 month = {next_month.date()}")
How do I debug date formatting issues?
from datetime import datetime
def debug_date_format(dt, format_string):
"""Debug date formatting by showing each component."""
print(f"Original datetime: {dt}")
print(f"Format string: '{format_string}'")
try:
formatted = dt.strftime(format_string)
print(f"Result: '{formatted}'")
# Break down format components
format_parts = [
('%Y', 'Full year'),
('%y', '2-digit year'),
('%m', 'Month (01-12)'),
('%B', 'Full month name'),
('%b', 'Short month name'),
('%d', 'Day (01-31)'),
('%H', 'Hour 24h (00-23)'),
('%I', 'Hour 12h (01-12)'),
('%M', 'Minute (00-59)'),
('%S', 'Second (00-59)'),
('%p', 'AM/PM'),
('%A', 'Full weekday'),
('%a', 'Short weekday'),
]
print("Components:")
for code, desc in format_parts:
if code in format_string:
component_value = dt.strftime(code)
print(f" {code} ({desc}): '{component_value}'")
return formatted
except ValueError as e:
print(f"Error: {e}")
return None
# Example debugging session
dt = datetime(2025, 9, 19, 14, 30, 45)
debug_date_format(dt, "%Y-%m-%d %I:%M %p")
How do I handle date validation in user input?
from datetime import datetime, date
import re
class DateValidator:
"""Comprehensive date validation with helpful error messages."""
def __init__(self):
self.formats = [
("%Y-%m-%d", "YYYY-MM-DD"),
("%m/%d/%Y", "MM/DD/YYYY"),
("%d/%m/%Y", "DD/MM/YYYY"),
("%B %d, %Y", "Month DD, YYYY"),
("%b %d, %Y", "Mon DD, YYYY"),
]
def validate_date_string(self, date_string, min_date=None, max_date=None):
"""Validate and parse date string with comprehensive error handling."""
if not date_string or not date_string.strip():
return False, "Date cannot be empty"
date_string = date_string.strip()
# Try parsing with known formats
parsed_date = None
for format_code, format_name in self.formats:
try:
parsed_date = datetime.strptime(date_string, format_code)
break
except ValueError:
continue
if not parsed_date:
format_examples = [name for _, name in self.formats]
return False, f"Invalid date format. Try: {', '.join(format_examples)}"
# Validate date range
if min_date and parsed_date.date() < min_date:
return False, f"Date must be after {min_date}"
if max_date and parsed_date.date() > max_date:
return False, f"Date must be before {max_date}"
# Additional validations
current_year = datetime.now().year
if parsed_date.year < 1900 or parsed_date.year > current_year + 100:
return False, f"Year must be between 1900 and {current_year + 100}"
return True, parsed_date.date()
def validate_age(self, birth_date_string, min_age=0, max_age=150):
"""Validate birth date and calculate age."""
is_valid, result = self.validate_date_string(
birth_date_string,
max_date=date.today() # Can't be in future
)
if not is_valid:
return False, result
birth_date = result
today = date.today()
age = today.year - birth_date.year - ((today.month, today.day) < (birth_date.month, birth_date.day))
if age < min_age:
return False, f"Age must be at least {min_age}"
if age > max_age:
return False, f"Age cannot exceed {max_age}"
return True, {"birth_date": birth_date, "age": age}
# Example usage
validator = DateValidator()
test_inputs = [
"2025-09-19",
"09/19/2025",
"September 19, 2025",
"invalid date",
"2030-01-01",
"1990-05-15",
]
print("Date validation examples:")
for test_input in test_inputs:
is_valid, result = validator.validate_date_string(
test_input,
min_date=date(2020, 1, 1),
max_date=date(2025, 12, 31)
)
if is_valid:
print(f"✓ '{test_input}' → {result}")
else:
print(f"✗ '{test_input}' → {result}")
print("\nAge validation examples:")
birth_dates = ["1990-05-15", "2010-01-01", "1850-01-01"]
for birth_date in birth_dates:
is_valid, result = validator.validate_age(birth_date, min_age=18)
if is_valid:
print(f"✓ Born {birth_date} → Age {result['age']}")
else:
print(f"✗ Born {birth_date} → {result}")
Reference
- Python Docs – Datetime
- Python Docs – Zoneinfo
- strftime.org – Clean date format reference
- Dateutil Documentation
- Time Zone Database - IANA timezone data
- ISO 8601 - International date/time standard
- RFC 2822 - Email date format standard