Python Date and Time
Python provides powerful modules for working with dates and times. Learn how to use datetime, time, and calendar modules for date manipulation, formatting, and calculations.
Working with Dates and Times
Python's datetime module is the primary way to work with dates and times. It provides classes for manipulating dates and times in both simple and complex ways.
"Time is an illusion. But datetime objects are real."
Current Date and Time
Get the current date and time:
from datetime import datetime, date, time
# Current date and time
now = datetime.now()
print("Current date and time:", now)
print("Type:", type(now))
# Current date only
today = date.today()
print("Today's date:", today)
# Current time only
current_time = datetime.now().time()
print("Current time:", current_time)
# Specific components
print("Year:", now.year)
print("Month:", now.month)
print("Day:", now.day)
print("Hour:", now.hour)
print("Minute:", now.minute)
print("Second:", now.second)
print("Microsecond:", now.microsecond)
Creating DateTime Objects
Create specific dates and times:
from datetime import datetime, date, time
# Create specific datetime
dt = datetime(2023, 12, 25, 10, 30, 45)
print("Christmas morning:", dt)
# Create date object
d = date(2023, 12, 25)
print("Christmas date:", d)
# Create time object
t = time(10, 30, 45)
print("Time:", t)
# Combine date and time
combined = datetime.combine(d, t)
print("Combined:", combined)
# From timestamp (seconds since epoch)
timestamp = 1703500245 # Example timestamp
dt_from_ts = datetime.fromtimestamp(timestamp)
print("From timestamp:", dt_from_ts)
# From ISO format string
iso_string = "2023-12-25T10:30:45"
dt_from_iso = datetime.fromisoformat(iso_string)
print("From ISO:", dt_from_iso)
DateTime Formatting
Format dates for display:
from datetime import datetime
now = datetime.now()
# Common formats
print("Default format:", now)
print("ISO format:", now.isoformat())
print("Date only:", now.date())
print("Time only:", now.time())
# Custom formatting with strftime
print("Formatted date:", now.strftime("%Y-%m-%d"))
print("Formatted time:", now.strftime("%H:%M:%S"))
print("Full format:", now.strftime("%A, %B %d, %Y at %I:%M %p"))
print("Short format:", now.strftime("%m/%d/%Y %H:%M"))
# Common strftime codes:
# %Y - Year (4 digits)
# %m - Month (01-12)
# %d - Day (01-31)
# %H - Hour (00-23)
# %M - Minute (00-59)
# %S - Second (00-59)
# %A - Full weekday name
# %B - Full month name
# %I - Hour (01-12)
# %p - AM/PM
Parsing Date Strings
Convert strings to datetime objects:
from datetime import datetime
# Using strptime
date_string = "2023-12-25 10:30:45"
dt = datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S")
print("Parsed datetime:", dt)
# Different formats
formats = [
"25/12/2023",
"12/25/2023",
"December 25, 2023",
"25-Dec-2023",
"2023/12/25"
]
format_strings = [
"%d/%m/%Y",
"%m/%d/%Y",
"%B %d, %Y",
"%d-%b-%Y",
"%Y/%m/%d"
]
for fmt_str, fmt in zip(formats, format_strings):
try:
parsed = datetime.strptime(fmt_str, fmt)
print(f"{fmt_str} -> {parsed.date()}")
except ValueError as e:
print(f"Error parsing {fmt_str}: {e}")
# Using dateutil parser (more flexible)
from dateutil import parser
flexible_dates = [
"today",
"tomorrow",
"next week",
"2023-12-25",
"12/25/2023",
"December 25th, 2023"
]
for date_str in flexible_dates:
try:
parsed = parser.parse(date_str)
print(f"'{date_str}' -> {parsed}")
except:
print(f"Could not parse: {date_str}")
Date Arithmetic
Add and subtract time periods:
from datetime import datetime, timedelta, date
# Current date
today = date.today()
print("Today:", today)
# Add days
tomorrow = today + timedelta(days=1)
print("Tomorrow:", tomorrow)
next_week = today + timedelta(weeks=1)
print("Next week:", next_week)
# Subtract days
yesterday = today - timedelta(days=1)
print("Yesterday:", yesterday)
# Date differences
date1 = date(2023, 12, 25)
date2 = date(2024, 1, 1)
difference = date2 - date1
print(f"Days between Christmas and New Year: {difference.days}")
# With datetime objects
now = datetime.now()
future = now + timedelta(hours=2, minutes=30)
print(f"Now: {now}")
print(f"In 2.5 hours: {future}")
# Time differences
past = now - timedelta(days=7)
time_diff = now - past
print(f"Time difference: {time_diff}")
print(f"Total seconds: {time_diff.total_seconds()}")
Working with Timezones
Handle different timezones:
from datetime import datetime, timezone, timedelta
import pytz
# UTC timezone
utc_now = datetime.now(timezone.utc)
print("UTC time:", utc_now)
# Create timezone-aware datetime
eastern = timezone(timedelta(hours=-5)) # EST
dt_eastern = datetime(2023, 12, 25, 10, 30, tzinfo=eastern)
print("Eastern time:", dt_eastern)
# Using pytz for proper timezone handling
if 'pytz' in globals():
# New York timezone
nyc_tz = pytz.timezone('America/New_York')
nyc_time = nyc_tz.localize(datetime(2023, 12, 25, 10, 30))
print("NYC time:", nyc_time)
# Convert to UTC
utc_time = nyc_time.astimezone(pytz.UTC)
print("UTC equivalent:", utc_time)
# Convert to London time
london_tz = pytz.timezone('Europe/London')
london_time = nyc_time.astimezone(london_tz)
print("London time:", london_time)
# Timezone conversion
naive_dt = datetime(2023, 12, 25, 10, 30)
# Make it timezone-aware (assuming it's in UTC)
aware_dt = naive_dt.replace(tzinfo=timezone.utc)
print("Timezone-aware:", aware_dt)
# Convert to different timezone
est_tz = timezone(timedelta(hours=-5))
est_time = aware_dt.astimezone(est_tz)
print("EST time:", est_time)
Calendar Operations
Use the calendar module:
import calendar
from datetime import date
# Current year calendar
year = 2024
print(f"Calendar for {year}:")
print(calendar.calendar(year))
# Month calendar
month = 12
print(f"\nCalendar for December {year}:")
print(calendar.month(year, month))
# Check if year is leap year
print(f"Is {year} a leap year? {calendar.isleap(year)}")
print(f"Is 2023 a leap year? {calendar.isleap(2023)}")
# Days in month
days_in_dec = calendar.monthrange(year, month)[1]
print(f"Days in December {year}: {days_in_dec}")
# Weekday of first day of month
first_weekday, days = calendar.monthrange(year, month)
weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
print(f"December {year} starts on a {weekdays[first_weekday]}")
# Get all days in a month
month_days = calendar.monthcalendar(year, month)
print("December calendar:")
for week in month_days:
print(week)
# Find day of week for specific date
specific_date = date(2023, 12, 25)
weekday_num = specific_date.weekday() # 0=Monday, 6=Sunday
weekday_name = weekdays[weekday_num]
print(f"December 25, 2023 is a {weekday_name}")
Time Module
Basic time operations:
import time
# Current timestamp (seconds since epoch)
current_time = time.time()
print(f"Current timestamp: {current_time}")
# Sleep for seconds
print("Sleeping for 2 seconds...")
time.sleep(2)
print("Awake!")
# Convert timestamp to struct_time
struct_time = time.localtime(current_time)
print("Structured time:", struct_time)
# Format time
formatted = time.strftime("%Y-%m-%d %H:%M:%S", struct_time)
print("Formatted time:", formatted)
# Parse time string
time_string = "2023-12-25 10:30:45"
parsed_time = time.strptime(time_string, "%Y-%m-%d %H:%M:%S")
print("Parsed time:", parsed_time)
# Time tuple components
print("Year:", parsed_time.tm_year)
print("Month:", parsed_time.tm_mon)
print("Day:", parsed_time.tm_mday)
print("Hour:", parsed_time.tm_hour)
print("Minute:", parsed_time.tm_min)
print("Second:", parsed_time.tm_sec)
print("Weekday:", parsed_time.tm_wday) # 0=Monday
print("Day of year:", parsed_time.tm_yday)
Practical Examples
from datetime import datetime, timedelta, date
import calendar
def calculate_age(birth_date):
"""Calculate age from birth date"""
today = date.today()
age = today.year - birth_date.year
if (today.month, today.day) < (birth_date.month, birth_date.day):
age -= 1
return age
def days_until_birthday(birth_date):
"""Calculate days until next birthday"""
today = date.today()
next_birthday = date(today.year, birth_date.month, birth_date.day)
if next_birthday < today:
next_birthday = date(today.year + 1, birth_date.month, birth_date.day)
return (next_birthday - today).days
def format_duration(seconds):
"""Format seconds into readable duration"""
days, remainder = divmod(seconds, 86400)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
parts = []
if days > 0:
parts.append(f"{days} days")
if hours > 0:
parts.append(f"{hours} hours")
if minutes > 0:
parts.append(f"{minutes} minutes")
if seconds > 0:
parts.append(f"{seconds} seconds")
return ", ".join(parts) if parts else "0 seconds"
# Usage examples
birth_date = date(1990, 5, 15)
print(f"Age: {calculate_age(birth_date)}")
print(f"Days until birthday: {days_until_birthday(birth_date)}")
# Duration formatting
durations = [65, 3665, 86465, 31536065]
for duration in durations:
print(f"{duration} seconds = {format_duration(duration)}")
def get_business_days(start_date, end_date):
"""Get number of business days between two dates"""
business_days = 0
current_date = start_date
while current_date <= end_date:
if current_date.weekday() < 5: # Monday to Friday
business_days += 1
current_date += timedelta(days=1)
return business_days
start = date(2023, 12, 20)
end = date(2024, 1, 5)
print(f"Business days: {get_business_days(start, end)}")
def next_weekday(start_date, weekday):
"""Find next occurrence of specific weekday"""
days_ahead = weekday - start_date.weekday()
if days_ahead <= 0:
days_ahead += 7
return start_date + timedelta(days=days_ahead)
today = date.today()
next_monday = next_weekday(today, 0) # 0 = Monday
next_friday = next_weekday(today, 4) # 4 = Friday
print(f"Next Monday: {next_monday}")
print(f"Next Friday: {next_friday}")
Best Practices
- Use timezone-aware datetime objects: Avoid naive datetime
- Store dates as UTC in databases: Convert for display
- Use ISO format for string representation: datetime.isoformat()
- Handle daylight saving time carefully: Use pytz library
- Use date objects for date-only operations: Not datetime
- Validate date inputs: Check for valid dates
- Use timedelta for date arithmetic: Not manual calculations
- Cache strftime format strings: For performance
- Use calendar for complex date operations: Month calculations
- Document timezone assumptions: In your code
Common Pitfalls
- Mixing naive and aware datetime objects: Causes errors
- February 29 on non-leap years: Validate dates
- Month/day order confusion: US vs international formats
- Time zone conversion errors: Double conversion
- Off-by-one errors in date ranges: Inclusive vs exclusive
- Timestamp precision loss: Microseconds in databases
- Locale-dependent formatting: Use explicit formats
Working with dates and times in Python is straightforward with the datetime module, but requires careful attention to timezones and formatting. Always consider whether you need date-only, time-only, or full datetime objects for your use case.