Handling dates and times correctly is tricky. Here's how to do it in Python.

Basic Types

from datetime import date, time, datetime, timedelta
 
# Date (year, month, day)
d = date(2026, 3, 21)
d = date.today()
 
# Time (hour, minute, second, microsecond)
t = time(14, 30, 0)
 
# Datetime (date + time)
dt = datetime(2026, 3, 21, 14, 30, 0)
dt = datetime.now()
 
# Timedelta (duration)
delta = timedelta(days=7, hours=3)

Current Date/Time

from datetime import datetime, date
 
# Current
datetime.now()      # Local datetime
date.today()        # Local date
 
# UTC
datetime.utcnow()   # Deprecated in 3.12
datetime.now(timezone.utc)  # Preferred

Creating Datetimes

from datetime import datetime
 
# From components
dt = datetime(2026, 3, 21, 14, 30, 0)
 
# From timestamp
dt = datetime.fromtimestamp(1711036200)
 
# From string (ISO format)
dt = datetime.fromisoformat("2026-03-21T14:30:00")
 
# From string (custom format)
dt = datetime.strptime("21/03/2026 14:30", "%d/%m/%Y %H:%M")

Formatting

dt = datetime(2026, 3, 21, 14, 30)
 
# ISO format
dt.isoformat()  # "2026-03-21T14:30:00"
 
# Custom format
dt.strftime("%Y-%m-%d")       # "2026-03-21"
dt.strftime("%B %d, %Y")      # "March 21, 2026"
dt.strftime("%I:%M %p")       # "02:30 PM"
dt.strftime("%A, %B %d")      # "Saturday, March 21"

Format Codes

CodeMeaningExample
%YYear (4 digits)2026
%mMonth (01-12)03
%dDay (01-31)21
%HHour 24h (00-23)14
%IHour 12h (01-12)02
%MMinute (00-59)30
%SSecond (00-59)00
%pAM/PMPM
%AWeekday nameSaturday
%BMonth nameMarch
%zUTC offset+0000

Arithmetic

from datetime import datetime, timedelta
 
now = datetime.now()
 
# Add/subtract time
tomorrow = now + timedelta(days=1)
last_week = now - timedelta(weeks=1)
later = now + timedelta(hours=3, minutes=30)
 
# Difference between datetimes
dt1 = datetime(2026, 3, 21)
dt2 = datetime(2026, 4, 1)
diff = dt2 - dt1  # timedelta(days=11)
diff.days         # 11
diff.total_seconds()  # 950400.0

Comparing

dt1 = datetime(2026, 3, 21)
dt2 = datetime(2026, 4, 1)
 
dt1 < dt2   # True
dt1 == dt2  # False
dt1 != dt2  # True
 
# Check if in range
start = datetime(2026, 1, 1)
end = datetime(2026, 12, 31)
start <= dt1 <= end  # True

Timezones

from datetime import datetime, timezone, timedelta
 
# UTC
utc_now = datetime.now(timezone.utc)
 
# Custom offset
eastern = timezone(timedelta(hours=-5))
dt = datetime.now(eastern)
 
# Using zoneinfo (Python 3.9+)
from zoneinfo import ZoneInfo
 
eastern = ZoneInfo("America/New_York")
pacific = ZoneInfo("America/Los_Angeles")
 
dt = datetime.now(eastern)
dt_pacific = dt.astimezone(pacific)

Timezone Best Practices

from datetime import datetime, timezone
 
# Always store in UTC
utc_time = datetime.now(timezone.utc)
 
# Convert to local for display
from zoneinfo import ZoneInfo
local_tz = ZoneInfo("America/New_York")
local_time = utc_time.astimezone(local_tz)

Components

dt = datetime(2026, 3, 21, 14, 30, 45)
 
dt.year        # 2026
dt.month       # 3
dt.day         # 21
dt.hour        # 14
dt.minute      # 30
dt.second      # 45
dt.weekday()   # 5 (Saturday, 0=Monday)
dt.date()      # date(2026, 3, 21)
dt.time()      # time(14, 30, 45)

Replace Components

dt = datetime(2026, 3, 21, 14, 30)
 
# Create new datetime with changed values
dt.replace(year=2027)        # 2027-03-21 14:30
dt.replace(hour=0, minute=0) # 2026-03-21 00:00

Common Patterns

Start/end of day

def start_of_day(dt):
    return dt.replace(hour=0, minute=0, second=0, microsecond=0)
 
def end_of_day(dt):
    return dt.replace(hour=23, minute=59, second=59, microsecond=999999)

Date range

def date_range(start, end):
    current = start
    while current <= end:
        yield current
        current += timedelta(days=1)
 
for d in date_range(date(2026, 3, 1), date(2026, 3, 7)):
    print(d)

Age calculation

def calculate_age(birthdate):
    today = date.today()
    age = today.year - birthdate.year
    if (today.month, today.day) < (birthdate.month, birthdate.day):
        age -= 1
    return age

Human-readable relative time

def time_ago(dt):
    diff = datetime.now() - dt
    seconds = diff.total_seconds()
    
    if seconds < 60:
        return "just now"
    if seconds < 3600:
        return f"{int(seconds // 60)} minutes ago"
    if seconds < 86400:
        return f"{int(seconds // 3600)} hours ago"
    return f"{diff.days} days ago"

Quick Reference

from datetime import datetime, date, time, timedelta, timezone
 
# Create
datetime.now()
datetime(2026, 3, 21, 14, 30)
datetime.fromisoformat("2026-03-21T14:30:00")
datetime.strptime(string, format)
 
# Format
dt.isoformat()
dt.strftime(format)
 
# Arithmetic
dt + timedelta(days=1)
dt2 - dt1  # Returns timedelta
 
# Components
dt.year, dt.month, dt.day
dt.hour, dt.minute, dt.second
dt.date(), dt.time()
 
# Timezone
datetime.now(timezone.utc)
dt.astimezone(new_tz)

Always use timezone-aware datetimes in production. Store UTC, display local.

React to this post: