Available for day contractsFrom 21st September I have availability for day and half day contracts. Please contact for more information.

Contact →
mikepreston.org

Python DateTime

Comprehensive guide to date and time manipulation in Python using the datetime module.

Python DateTime Cheatsheet

Comprehensive guide to date and time manipulation in Python using the datetime module.

Overview

Python's datetime module provides classes for manipulating dates and times, from simple date arithmetic to complex timezone-aware operations. It's essential for timestamps, scheduling, data analysis, and logging.

Common Operationsdatetime ModuledatetimedatetimetimedeltatimezoneParse StringsFormat OutputArithmeticTimezone ConvertTimestampsCommon Operationsdatetime ModuledatetimedatetimetimedeltatimezoneParse StringsFormat OutputArithmeticTimezone ConvertTimestamps

Installation

The datetime module is part of Python's standard library - no installation required.

from datetime import datetime, date, time, timedelta, timezone

datetime Module Basics

Key Concepts

  • datetime - Combines date and time into a single object
  • date - Represents a date (year, month, day) without time
  • time - Represents time (hour, minute, second, microsecond) without date
  • timedelta - Represents a duration or difference between two dates/times
  • strptime - Parse a string into a datetime object
  • strftime - Format a datetime object as a string
strptimestrftimetimedeltatimestampfromtimestampStringdatetime objectFormatted StringNew datetimeUnix TimestampstrptimestrftimetimedeltatimestampfromtimestampStringdatetime objectFormatted StringNew datetimeUnix Timestamp

Common Patterns

from datetime import datetime, date, time, timedelta, timezone

# Get current date and time
now = datetime.now()                    # Local time
utc_now = datetime.now(timezone.utc)    # UTC time (aware; utcnow() is deprecated since 3.12)
today = date.today()                    # Current date only

# Create specific datetime
dt = datetime(2024, 12, 25, 14, 30, 0)  # Christmas 2024, 2:30 PM
d = date(2024, 12, 25)                   # Date only
t = time(14, 30, 0)                      # Time only

# Parse string to datetime (strptime)
dt = datetime.strptime('2024-12-25 14:30:00', '%Y-%m-%d %H:%M:%S')

# Format datetime to string (strftime)
formatted = dt.strftime('%d/%m/%Y %H:%M')  # '25/12/2024 14:30'

# Time differences with timedelta
delta = timedelta(days=7, hours=3, minutes=30)
next_week = now + delta

Examples

Getting Current Date and Time

from datetime import datetime, date, time

# Current datetime
now = datetime.now()
print(f"Now: {now}")                    # 2024-03-15 10:30:45.123456
print(f"Date: {now.date()}")            # 2024-03-15
print(f"Time: {now.time()}")            # 10:30:45.123456

# Access individual components
print(f"Year: {now.year}")              # 2024
print(f"Month: {now.month}")            # 3
print(f"Day: {now.day}")                # 15
print(f"Hour: {now.hour}")              # 10
print(f"Minute: {now.minute}")          # 30
print(f"Second: {now.second}")          # 45
print(f"Microsecond: {now.microsecond}")# 123456
print(f"Weekday: {now.weekday()}")      # 4 (Friday, 0=Monday)

Parsing Strings with strptime

from datetime import datetime

# Common date formats
dt1 = datetime.strptime('2024-03-15', '%Y-%m-%d')
dt2 = datetime.strptime('15/03/2024', '%d/%m/%Y')
dt3 = datetime.strptime('March 15, 2024', '%B %d, %Y')
dt4 = datetime.strptime('2024-03-15T10:30:00', '%Y-%m-%dT%H:%M:%S')

# With time component
dt5 = datetime.strptime('15-Mar-2024 10:30:45', '%d-%b-%Y %H:%M:%S')

# 12-hour format with AM/PM
dt6 = datetime.strptime('03/15/2024 02:30 PM', '%m/%d/%Y %I:%M %p')

print(dt6)  # 2024-03-15 14:30:00

Formatting with strftime

from datetime import datetime

now = datetime.now()

# Common output formats
print(now.strftime('%Y-%m-%d'))           # 2024-03-15
print(now.strftime('%d/%m/%Y'))           # 15/03/2024
print(now.strftime('%B %d, %Y'))          # March 15, 2024
print(now.strftime('%A, %d %B %Y'))       # Friday, 15 March 2024
print(now.strftime('%H:%M:%S'))           # 10:30:45
print(now.strftime('%I:%M %p'))           # 10:30 AM
print(now.strftime('%Y-%m-%dT%H:%M:%S'))  # ISO 8601 format

# Combined formats
print(now.strftime('%d %b %Y, %H:%M'))    # 15 Mar 2024, 10:30
print(now.strftime('%a %d/%m/%y %H:%M'))  # Fri 15/03/24 10:30

Working with timedelta

from datetime import datetime, timedelta

now = datetime.now()

# Create timedeltas
one_day = timedelta(days=1)
one_week = timedelta(weeks=1)
two_hours = timedelta(hours=2)
complex_delta = timedelta(days=5, hours=3, minutes=30, seconds=45)

# Add and subtract
tomorrow = now + one_day
yesterday = now - one_day
next_week = now + one_week
two_hours_ago = now - two_hours

# Calculate differences
future_date = datetime(2024, 12, 31)
days_until = future_date - now
print(f"Days until: {days_until.days}")
print(f"Total seconds: {days_until.total_seconds()}")

# Multiply and divide timedeltas
double_delta = one_week * 2  # 14 days
half_day = one_day / 2       # 12 hours

Timezone Handling

Key Concepts

  • Naive datetime - No timezone information attached
  • Aware datetime - Contains timezone information
  • UTC - Coordinated Universal Time, the standard reference
  • timezone - Class for creating fixed offset timezones
  • zoneinfo - Python 3.9+ module for IANA timezone database
attach timezoneastimezoneutcoffsetTimezonesUTCLocalCustom offsetIANA zonesNaive datetimeAware datetimeDifferent timezoneOffset from UTCattach timezoneastimezoneutcoffsetTimezonesUTCLocalCustom offsetIANA zonesNaive datetimeAware datetimeDifferent timezoneOffset from UTC

Common Patterns

from datetime import datetime, timezone, timedelta
from zoneinfo import ZoneInfo  # Python 3.9+

# Create UTC timezone
utc = timezone.utc

# Create custom offset timezone
bst = timezone(timedelta(hours=1))  # British Summer Time

# Get current time with timezone
now_utc = datetime.now(timezone.utc)
now_local = datetime.now().astimezone()  # Local timezone

# Convert between timezones
dt_utc = datetime.now(timezone.utc)
dt_london = dt_utc.astimezone(ZoneInfo('Europe/London'))
dt_tokyo = dt_utc.astimezone(ZoneInfo('Asia/Tokyo'))

Examples

Working with UTC

from datetime import datetime, timezone

# Current time in UTC (recommended approach)
now_utc = datetime.now(timezone.utc)
print(f"UTC now: {now_utc}")  # 2024-03-15 10:30:45.123456+00:00

# Create UTC datetime
dt_utc = datetime(2024, 3, 15, 10, 30, tzinfo=timezone.utc)

# Convert naive to UTC (assuming it's already UTC)
naive_dt = datetime(2024, 3, 15, 10, 30)
utc_dt = naive_dt.replace(tzinfo=timezone.utc)

# Get UTC offset
print(f"UTC offset: {now_utc.utcoffset()}")  # 0:00:00
print(f"Timezone name: {now_utc.tzname()}")  # UTC

Converting Between Timezones

from datetime import datetime, timezone, timedelta
from zoneinfo import ZoneInfo  # Python 3.9+

# Create aware datetime in UTC
dt_utc = datetime(2024, 3, 15, 12, 0, tzinfo=timezone.utc)

# Convert to different timezones
dt_london = dt_utc.astimezone(ZoneInfo('Europe/London'))
dt_paris = dt_utc.astimezone(ZoneInfo('Europe/Paris'))
dt_new_york = dt_utc.astimezone(ZoneInfo('America/New_York'))
dt_tokyo = dt_utc.astimezone(ZoneInfo('Asia/Tokyo'))

print(f"UTC:      {dt_utc}")       # 12:00+00:00
print(f"London:   {dt_london}")    # 12:00+00:00 or 13:00+01:00 (DST)
print(f"Paris:    {dt_paris}")     # 13:00+01:00 or 14:00+02:00 (DST)
print(f"New York: {dt_new_york}")  # 08:00-04:00 or 07:00-05:00
print(f"Tokyo:    {dt_tokyo}")     # 21:00+09:00

Custom Timezone Offsets

from datetime import datetime, timezone, timedelta

# Create timezone with fixed offset
utc_plus_5_30 = timezone(timedelta(hours=5, minutes=30), name='IST')
utc_minus_8 = timezone(timedelta(hours=-8), name='PST')

# Create datetime with custom timezone
dt_india = datetime(2024, 3, 15, 17, 30, tzinfo=utc_plus_5_30)
print(f"India: {dt_india}")  # 2024-03-15 17:30:00+05:30

# Convert to UTC
dt_utc = dt_india.astimezone(timezone.utc)
print(f"UTC: {dt_utc}")  # 2024-03-15 12:00:00+00:00

Local Time Operations

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

# Get local timezone-aware datetime
local_now = datetime.now().astimezone()
print(f"Local: {local_now}")
print(f"Timezone: {local_now.tzinfo}")

# Get system's local timezone
local_tz = datetime.now().astimezone().tzinfo

# Explicitly use local timezone
# This handles DST automatically
uk_tz = ZoneInfo('Europe/London')
dt_uk = datetime.now(uk_tz)
print(f"UK time: {dt_uk}")

# Check if in daylight saving time
is_dst = bool(dt_uk.dst())
print(f"DST active: {is_dst}")

Common Date Operations

Key Concepts

  • Date arithmetic - Add/subtract days, weeks, months using timedelta
  • Date comparison - Compare dates using standard operators
  • Date replacement - Modify specific components of a date
  • Calendar operations - Week numbers, day of year, leap years

Common Patterns

from datetime import datetime, date, timedelta
import calendar

# Add/subtract time
new_date = date.today() + timedelta(days=30)
past_date = datetime.now() - timedelta(weeks=2)

# Compare dates
is_future = date1 > date2
is_same_day = date1.date() == date2.date()

# Replace components
new_dt = dt.replace(year=2025, month=1)

# Calendar functions
is_leap = calendar.isleap(2024)
days_in_month = calendar.monthrange(2024, 2)[1]

Examples

Adding and Subtracting Days

from datetime import datetime, date, timedelta

today = date.today()

# Add days
tomorrow = today + timedelta(days=1)
next_week = today + timedelta(weeks=1)
in_30_days = today + timedelta(days=30)
in_90_days = today + timedelta(days=90)

# Subtract days
yesterday = today - timedelta(days=1)
last_week = today - timedelta(weeks=1)
last_month = today - timedelta(days=30)

print(f"Today: {today}")
print(f"In 30 days: {in_30_days}")
print(f"30 days ago: {last_month}")

# Working with datetime (includes time)
now = datetime.now()
in_two_hours = now + timedelta(hours=2)
thirty_mins_ago = now - timedelta(minutes=30)

Comparing Dates

from datetime import datetime, date

date1 = date(2024, 3, 15)
date2 = date(2024, 6, 20)
date3 = date(2024, 3, 15)

# Basic comparisons
print(date1 < date2)   # True (date1 is earlier)
print(date1 > date2)   # False
print(date1 == date3)  # True (same date)
print(date1 != date2)  # True
print(date1 <= date3)  # True

# Compare with today
today = date.today()
is_past = date1 < today
is_future = date2 > today

# Sort dates
dates = [date2, date1, date3]
sorted_dates = sorted(dates)
print(sorted_dates)  # Ascending order

# Find min/max
earliest = min(dates)
latest = max(dates)

# Check if date is between two dates
start = date(2024, 1, 1)
end = date(2024, 12, 31)
is_in_range = start <= date1 <= end
print(f"In 2024: {is_in_range}")  # True

Calculating Date Differences

from datetime import datetime, date

# Difference between dates
date1 = date(2024, 1, 1)
date2 = date(2024, 12, 31)
diff = date2 - date1
print(f"Days between: {diff.days}")  # 365

# Difference between datetimes
dt1 = datetime(2024, 3, 15, 10, 0, 0)
dt2 = datetime(2024, 3, 15, 14, 30, 45)
diff = dt2 - dt1
print(f"Hours: {diff.seconds // 3600}")      # 4
print(f"Minutes: {(diff.seconds % 3600) // 60}")  # 30
print(f"Total seconds: {diff.total_seconds()}")   # 16245.0

# Days until an event
today = date.today()
christmas = date(today.year, 12, 25)
if christmas < today:
    christmas = date(today.year + 1, 12, 25)
days_until_christmas = (christmas - today).days
print(f"Days until Christmas: {days_until_christmas}")

# Age calculation
birth_date = date(1990, 5, 15)
today = date.today()
age = today.year - birth_date.year
if today.month < birth_date.month or \
   (today.month == birth_date.month and today.day < birth_date.day):
    age -= 1
print(f"Age: {age} years")

Replacing Date Components

from datetime import datetime, date

dt = datetime(2024, 3, 15, 10, 30, 45)

# Replace individual components
new_year = dt.replace(year=2025)
first_of_month = dt.replace(day=1)
midnight = dt.replace(hour=0, minute=0, second=0, microsecond=0)
end_of_day = dt.replace(hour=23, minute=59, second=59)

print(f"Original: {dt}")
print(f"New year: {new_year}")
print(f"First of month: {first_of_month}")
print(f"Midnight: {midnight}")

# Get start and end of month
start_of_month = dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)

import calendar
last_day = calendar.monthrange(dt.year, dt.month)[1]
end_of_month = dt.replace(day=last_day, hour=23, minute=59, second=59)

print(f"Month start: {start_of_month}")
print(f"Month end: {end_of_month}")

Week and Calendar Operations

from datetime import datetime, date
import calendar

dt = datetime(2024, 3, 15)  # Friday

# Day of week (0=Monday, 6=Sunday)
print(f"Weekday: {dt.weekday()}")      # 4 (Friday)
print(f"ISO weekday: {dt.isoweekday()}")  # 5 (1=Monday, 7=Sunday)

# Week number
print(f"Week number: {dt.strftime('%W')}")  # Week starting Monday
print(f"ISO week: {dt.isocalendar().week}")  # ISO week number

# ISO calendar (year, week, weekday)
iso_cal = dt.isocalendar()
print(f"ISO: {iso_cal.year}-W{iso_cal.week}-{iso_cal.weekday}")

# Day of year
day_of_year = dt.timetuple().tm_yday
print(f"Day of year: {day_of_year}")  # 75

# Check leap year
year = 2024
is_leap = calendar.isleap(year)
print(f"{year} is leap year: {is_leap}")  # True

# Days in month
days_in_feb = calendar.monthrange(2024, 2)[1]
print(f"Days in Feb 2024: {days_in_feb}")  # 29

# First weekday of month (0=Monday)
first_weekday = calendar.monthrange(2024, 3)[0]
print(f"March 2024 starts on: {calendar.day_name[first_weekday]}")

Unix Timestamps

Key Concepts

  • Unix timestamp - Seconds since 1 January 1970 00:00:00 UTC (Unix epoch)
  • fromtimestamp - Convert timestamp to local datetime
  • utcfromtimestamp - Convert timestamp to UTC datetime (deprecated)
  • timestamp - Convert datetime to Unix timestamp
  • Milliseconds - JavaScript and some APIs use milliseconds
.timestampfromtimestamp/ 1000* 1000datetimeUnix timestampLocal datetimeSeconds to ms.timestampfromtimestamp/ 1000* 1000datetimeUnix timestampLocal datetimeSeconds to ms

Common Patterns

from datetime import datetime, timezone

# Current timestamp
timestamp = datetime.now().timestamp()

# Convert timestamp to datetime
dt = datetime.fromtimestamp(timestamp)  # Local time
dt_utc = datetime.fromtimestamp(timestamp, tz=timezone.utc)  # UTC

# Convert datetime to timestamp
ts = dt.timestamp()

# Milliseconds (for JavaScript interop)
ms_timestamp = int(datetime.now().timestamp() * 1000)
dt_from_ms = datetime.fromtimestamp(ms_timestamp / 1000)

Examples

Getting Current Timestamp

from datetime import datetime, timezone
import time

# Current Unix timestamp (seconds since epoch)
timestamp = datetime.now().timestamp()
print(f"Timestamp: {timestamp}")  # 1710502245.123456

# Using time module
timestamp_time = time.time()
print(f"Time module: {timestamp_time}")

# Integer timestamp (no microseconds)
int_timestamp = int(datetime.now().timestamp())
print(f"Integer: {int_timestamp}")  # 1710502245

# UTC timestamp (recommended)
utc_timestamp = datetime.now(timezone.utc).timestamp()
print(f"UTC timestamp: {utc_timestamp}")

Converting Timestamp to datetime

from datetime import datetime, timezone

timestamp = 1710502245  # Example timestamp

# To local datetime
dt_local = datetime.fromtimestamp(timestamp)
print(f"Local: {dt_local}")  # Depends on system timezone

# To UTC datetime (recommended)
dt_utc = datetime.fromtimestamp(timestamp, tz=timezone.utc)
print(f"UTC: {dt_utc}")  # 2024-03-15 11:30:45+00:00

# With specific timezone
from zoneinfo import ZoneInfo
dt_london = datetime.fromtimestamp(timestamp, tz=ZoneInfo('Europe/London'))
print(f"London: {dt_london}")

# Handle timestamps with microseconds
timestamp_micro = 1710502245.123456
dt = datetime.fromtimestamp(timestamp_micro, tz=timezone.utc)
print(f"With microseconds: {dt}")

Converting datetime to Timestamp

from datetime import datetime, timezone

# Current datetime to timestamp
now = datetime.now()
timestamp = now.timestamp()
print(f"Timestamp: {timestamp}")

# Specific datetime to timestamp
dt = datetime(2024, 3, 15, 12, 30, 45)
timestamp = dt.timestamp()  # Uses local timezone
print(f"Timestamp: {timestamp}")

# UTC datetime to timestamp
dt_utc = datetime(2024, 3, 15, 12, 30, 45, tzinfo=timezone.utc)
timestamp = dt_utc.timestamp()
print(f"UTC timestamp: {timestamp}")

# Be explicit about timezone for consistency
dt_aware = datetime(2024, 3, 15, 12, 30, 45, tzinfo=timezone.utc)
timestamp = dt_aware.timestamp()

Working with Milliseconds

from datetime import datetime, timezone

# Timestamp in milliseconds (JavaScript format)
ms_timestamp = 1710502245123

# Convert milliseconds to datetime
dt = datetime.fromtimestamp(ms_timestamp / 1000, tz=timezone.utc)
print(f"From ms: {dt}")

# Current time in milliseconds
now_ms = int(datetime.now(timezone.utc).timestamp() * 1000)
print(f"Now (ms): {now_ms}")

# Convert datetime to milliseconds
dt = datetime.now(timezone.utc)
ms = int(dt.timestamp() * 1000)
print(f"To ms: {ms}")

# Microseconds to milliseconds
microseconds = dt.microsecond
milliseconds = microseconds // 1000

Timestamp Range Queries

from datetime import datetime, timezone, timedelta

# Get timestamps for a date range
start_date = datetime(2024, 3, 1, tzinfo=timezone.utc)
end_date = datetime(2024, 3, 31, 23, 59, 59, tzinfo=timezone.utc)

start_ts = int(start_date.timestamp())
end_ts = int(end_date.timestamp())

print(f"Start: {start_ts}")
print(f"End: {end_ts}")

# Database query example
# SELECT * FROM events WHERE timestamp >= {start_ts} AND timestamp <= {end_ts}

# Last 24 hours
now = datetime.now(timezone.utc)
yesterday = now - timedelta(days=1)
last_24h_start = int(yesterday.timestamp())
last_24h_end = int(now.timestamp())

ISO 8601 Formatting

Key Concepts

  • ISO 8601 - International standard for date and time representation
  • Format - YYYY-MM-DDTHH:MM:SS.ssssss+HH:MM
  • Z suffix - Indicates UTC (Zulu time)
  • isoformat - Built-in method for ISO 8601 output
  • fromisoformat - Parse ISO 8601 strings (Python 3.7+)
2024-03-15T14:30:45.123456+00:002024-03-15T14:30:45.123456+00:00Date: YYYY-MM-DDSeparatorTime:HH:MM:SS.microsecondsTimezone offset2024-03-15T14:30:45.123456+00:002024-03-15T14:30:45.123456+00:00Date: YYYY-MM-DDSeparatorTime:HH:MM:SS.microsecondsTimezone offset

Common Patterns

from datetime import datetime, timezone, date, time

# Output ISO 8601
dt = datetime.now(timezone.utc)
iso_string = dt.isoformat()  # 2024-03-15T12:30:45.123456+00:00

# Parse ISO 8601
dt = datetime.fromisoformat('2024-03-15T12:30:45+00:00')

# Date only
d = date.fromisoformat('2024-03-15')
iso_date = d.isoformat()

# Time only
t = time.fromisoformat('12:30:45')
iso_time = t.isoformat()

Examples

Generating ISO 8601 Strings

from datetime import datetime, timezone, date, time

# Full ISO 8601 with timezone
dt = datetime.now(timezone.utc)
iso_full = dt.isoformat()
print(f"Full: {iso_full}")  # 2024-03-15T12:30:45.123456+00:00

# Without microseconds
iso_short = dt.replace(microsecond=0).isoformat()
print(f"Short: {iso_short}")  # 2024-03-15T12:30:45+00:00

# With custom separator
iso_space = dt.isoformat(sep=' ')
print(f"Space: {iso_space}")  # 2024-03-15 12:30:45.123456+00:00

# Truncate to specific precision
iso_seconds = dt.isoformat(timespec='seconds')
iso_minutes = dt.isoformat(timespec='minutes')
iso_hours = dt.isoformat(timespec='hours')
iso_ms = dt.isoformat(timespec='milliseconds')

print(f"Seconds: {iso_seconds}")  # 2024-03-15T12:30:45+00:00
print(f"Minutes: {iso_minutes}")  # 2024-03-15T12:30+00:00
print(f"Milliseconds: {iso_ms}")  # 2024-03-15T12:30:45.123+00:00

# Date only
d = date.today()
print(f"Date: {d.isoformat()}")  # 2024-03-15

# Time only
t = time(14, 30, 45)
print(f"Time: {t.isoformat()}")  # 14:30:45

Parsing ISO 8601 Strings

from datetime import datetime, date, time

# Parse full ISO 8601
dt = datetime.fromisoformat('2024-03-15T14:30:45')
print(f"Parsed: {dt}")

# With timezone
dt_tz = datetime.fromisoformat('2024-03-15T14:30:45+01:00')
print(f"With TZ: {dt_tz}")

# UTC with Z suffix (Python 3.11+)
# Before 3.11, replace 'Z' with '+00:00' first
iso_z = '2024-03-15T14:30:45Z'
dt_z = datetime.fromisoformat(iso_z)
print(f"From Z: {dt_z}")

# Parse date only
d = date.fromisoformat('2024-03-15')
print(f"Date: {d}")

# Parse time only
t = time.fromisoformat('14:30:45')
print(f"Time: {t}")

# Various ISO 8601 formats
formats = [
    '2024-03-15',
    '2024-03-15T14:30',
    '2024-03-15T14:30:45',
    '2024-03-15T14:30:45.123456',
    '2024-03-15T14:30:45+00:00',
    '2024-03-15 14:30:45',  # Space separator also works
]

for fmt in formats:
    try:
        parsed = datetime.fromisoformat(fmt)
        print(f"{fmt} -> {parsed}")
    except ValueError as e:
        print(f"{fmt} -> Error: {e}")

ISO Week Dates

from datetime import datetime, date

# ISO calendar returns (year, week, weekday)
dt = datetime(2024, 3, 15)
iso_cal = dt.isocalendar()
print(f"ISO year: {iso_cal.year}")
print(f"ISO week: {iso_cal.week}")
print(f"ISO weekday: {iso_cal.weekday}")  # 1-7 (Mon-Sun)

# Format as ISO week date
iso_week_date = f"{iso_cal.year}-W{iso_cal.week:02d}-{iso_cal.weekday}"
print(f"ISO week date: {iso_week_date}")  # 2024-W11-5

# Parse ISO week date (Python 3.8+)
from datetime import datetime
dt = datetime.strptime('2024-W11-5', '%G-W%V-%u')
print(f"From ISO week: {dt.date()}")  # 2024-03-15

API and Database Formats

from datetime import datetime, timezone

now = datetime.now(timezone.utc)

# Common API formats
api_formats = {
    'ISO 8601': now.isoformat(),
    'ISO compact': now.strftime('%Y%m%dT%H%M%SZ'),
    'RFC 2822': now.strftime('%a, %d %b %Y %H:%M:%S +0000'),
    'RFC 3339': now.isoformat().replace('+00:00', 'Z'),
}

for name, fmt in api_formats.items():
    print(f"{name}: {fmt}")

# Database formats
db_formats = {
    'MySQL datetime': now.strftime('%Y-%m-%d %H:%M:%S'),
    'PostgreSQL': now.isoformat(),
    'SQLite': now.strftime('%Y-%m-%d %H:%M:%S.%f'),
}

for name, fmt in db_formats.items():
    print(f"{name}: {fmt}")

# Elasticsearch / JSON
import json
json_dt = json.dumps({'timestamp': now.isoformat()})
print(f"JSON: {json_dt}")

Quick Reference

Format Codes

Code Description Example
%Y 4-digit year 2024
%y 2-digit year 24
%m Month (01-12) 03
%d Day (01-31) 15
%H Hour 24h (00-23) 14
%I Hour 12h (01-12) 02
%M Minute (00-59) 30
%S Second (00-59) 45
%f Microsecond 123456
%p AM/PM PM
%A Full weekday Friday
%a Short weekday Fri
%B Full month March
%b Short month Mar
%j Day of year 075
%W Week number (Mon) 11
%U Week number (Sun) 10
%z UTC offset +0000
%Z Timezone name UTC

Common Operations

Operation Code
Current datetime datetime.now()
Current UTC datetime.now(timezone.utc)
Current date date.today()
Parse string datetime.strptime(s, fmt)
Format string dt.strftime(fmt)
Add days dt + timedelta(days=n)
Subtract days dt - timedelta(days=n)
Date difference (dt2 - dt1).days
To timestamp dt.timestamp()
From timestamp datetime.fromtimestamp(ts)
To ISO 8601 dt.isoformat()
From ISO 8601 datetime.fromisoformat(s)
Replace component dt.replace(year=2025)
Attach timezone dt.replace(tzinfo=tz)
Convert timezone dt.astimezone(tz)

Timezone Quick Reference

Task Code
UTC timezone timezone.utc
Custom offset timezone(timedelta(hours=5))
IANA timezone ZoneInfo('Europe/London')
Make aware dt.replace(tzinfo=timezone.utc)
Convert zone dt.astimezone(new_tz)
Get offset dt.utcoffset()
Local to UTC local_dt.astimezone(timezone.utc)
UTC to local utc_dt.astimezone()

Common Issues and Solutions

Issue: Naive vs Aware Datetime Comparison

Problem: TypeError: can't compare offset-naive and offset-aware datetimes

Solution:

from datetime import datetime, timezone

naive_dt = datetime.now()
aware_dt = datetime.now(timezone.utc)

# Option 1: Make naive aware (if you know it's UTC)
naive_as_utc = naive_dt.replace(tzinfo=timezone.utc)
can_compare = naive_as_utc > aware_dt

# Option 2: Make aware naive (loses timezone info)
aware_as_naive = aware_dt.replace(tzinfo=None)
can_compare = naive_dt > aware_as_naive

# Best practice: Always use aware datetimes
dt1 = datetime.now(timezone.utc)
dt2 = datetime.now(timezone.utc)
can_compare = dt1 > dt2

Issue: strptime Format Mismatch

Problem: ValueError: time data 'X' does not match format 'Y'

Solution:

from datetime import datetime

date_string = '15/03/2024'

# Ensure format matches exactly
# Wrong: '%Y-%m-%d' expects 2024-03-15
# Right: '%d/%m/%Y' expects 15/03/2024
dt = datetime.strptime(date_string, '%d/%m/%Y')

# For variable formats, try multiple
formats = ['%Y-%m-%d', '%d/%m/%Y', '%m/%d/%Y', '%d-%m-%Y']

def parse_date(date_string):
    for fmt in formats:
        try:
            return datetime.strptime(date_string, fmt)
        except ValueError:
            continue
    raise ValueError(f"Unable to parse: {date_string}")

Issue: Daylight Saving Time Ambiguity

Problem: Ambiguous times during DST transitions

Solution:

from datetime import datetime
from zoneinfo import ZoneInfo

# During DST transition, some times occur twice
# Use fold attribute to disambiguate (Python 3.6+)
tz = ZoneInfo('Europe/London')

# 01:30 occurs twice on last Sunday of October
# fold=0 is first occurrence (before clocks go back)
# fold=1 is second occurrence (after clocks go back)
dt_first = datetime(2024, 10, 27, 1, 30, tzinfo=tz, fold=0)
dt_second = datetime(2024, 10, 27, 1, 30, tzinfo=tz, fold=1)

print(f"First (BST): {dt_first.isoformat()}")
print(f"Second (GMT): {dt_second.isoformat()}")

Issue: Timestamp Timezone Confusion

Problem: fromtimestamp() returns local time unexpectedly

Solution:

from datetime import datetime, timezone

timestamp = 1710502245

# This returns LOCAL time (confusing!)
local_dt = datetime.fromtimestamp(timestamp)
print(f"Local: {local_dt}")

# Always specify timezone explicitly
utc_dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
print(f"UTC: {utc_dt}")

# Or convert to your desired timezone
from zoneinfo import ZoneInfo
london_dt = datetime.fromtimestamp(timestamp, tz=ZoneInfo('Europe/London'))
print(f"London: {london_dt}")

Issue: Parsing ISO 8601 with Z Suffix

Problem: fromisoformat() doesn't recognise 'Z' (before Python 3.11)

Solution:

from datetime import datetime, timezone

iso_string = '2024-03-15T14:30:45.123Z'

# Python 3.11+: Works directly
dt = datetime.fromisoformat(iso_string)
print(f"Parsed: {dt}")

# Python 3.7-3.10: Replace Z with +00:00
# dt = datetime.fromisoformat(iso_string.replace('Z', '+00:00'))

# Alternative: Use strptime
dt = datetime.strptime(iso_string, '%Y-%m-%dT%H:%M:%S.%fZ')
dt = dt.replace(tzinfo=timezone.utc)

Issue: Month Arithmetic

Problem: Adding months isn't straightforward with timedelta

Solution:

from datetime import datetime
from dateutil.relativedelta import relativedelta  # pip install python-dateutil

dt = datetime(2024, 1, 31)

# timedelta doesn't support months directly
# This would fail: dt + timedelta(months=1)

# Use dateutil's relativedelta
next_month = dt + relativedelta(months=1)
print(f"Next month: {next_month}")  # 2024-02-29 (handles month end)

# Manual approach without dateutil
def add_months(dt, months):
    month = dt.month + months
    year = dt.year + (month - 1) // 12
    month = (month - 1) % 12 + 1

    import calendar
    max_day = calendar.monthrange(year, month)[1]
    day = min(dt.day, max_day)

    return dt.replace(year=year, month=month, day=day)

result = add_months(datetime(2024, 1, 31), 1)
print(f"Result: {result}")  # 2024-02-29

Issue: Performance with Many Datetime Operations

Problem: Slow performance when processing many dates

Solution:

from datetime import datetime, timezone

# Avoid repeated timezone lookups
from zoneinfo import ZoneInfo
tz = ZoneInfo('Europe/London')  # Cache the timezone

# Pre-compile format strings (strptime is slow)
# Use fromisoformat when possible (much faster)
dates = ['2024-03-15', '2024-03-16', '2024-03-17']
parsed = [datetime.fromisoformat(d) for d in dates]  # Fast

# For high-performance needs, consider:
# - pandas for bulk datetime operations
# - numpy's datetime64 for numerical operations
# - ciso8601 for fast ISO 8601 parsing

Related Topics

  • dateutil - Powerful extensions for datetime parsing and timezone handling
  • pytz - Historical timezone library (use zoneinfo for Python 3.9+)
  • arrow - Human-friendly datetime library with simpler API
  • pendulum - Timezone-aware datetime with natural language support
  • pandas datetime - Efficient datetime operations for data analysis
  • time module - Lower-level time functions and process timing