Date & Time
DateTime Formatting
Applications must display dates in user-friendly formats and parse dates from user input or files. Python's strftime() converts dates to strings using format codes, while strptime() parses strings back to dates. Mastering these functions enables proper date handling in APIs, logs, and user interfaces.
Common Patterns
%Y-%m-%d: 2025-01-29%H:%M:%S: 14:30:45%Y-%m-%d %H:%M:%S: 2025-01-29 14:30:45
Format Codes
%Y: 4-digit year%m: 2-digit month%d: 2-digit day%H: 24-hour (00-23)%M: minute%S: second
Locale-Aware Formatting
format.py
# Format to string
from datetime import datetime, date, time
# Format datetime
dt = datetime(2025, 1, 29, 14, 30, 45)
print("DateTime:", dt)
print()
# ISO format
print("ISO formats:")
print("ISO format:", dt.isoformat())
print("ISO date:", dt.date().isoformat())
print("ISO time:", dt.time().isoformat())
# Common patterns
print("\nCommon patterns:")
print("%Y-%m-%d %H:%M:%S:", dt.strftime("%Y-%m-%d %H:%M:%S"))
print("%m/%d/%Y:", dt.strftime("%m/%d/%Y"))
print("%d-%b-%Y:", dt.strftime("%d-%b-%Y"))
print("%A, %B %d, %Y:", dt.strftime("%A, %B %d, %Y"))
# Time formats
print("\nTime formats:")
print("24-hour:", dt.strftime("%H:%M:%S"))
print("12-hour:", dt.strftime("%I:%M %p"))
# Date only
d = date(2025, 1, 29)
print("\nDate only:")
print("ISO:", d.isoformat())
print("US:", d.strftime("%m/%d/%Y"))
print("EU:", d.strftime("%d/%m/%Y"))
print("Full:", d.strftime("%A, %B %d, %Y"))
# Time only
t = time(14, 30, 45)
print("\nTime only:")
print("ISO:", t.isoformat())
print("Simple:", t.strftime("%H:%M"))
print("12-hour:", t.strftime("%I:%M %p"))
# Default str()
print("\nDefault str():")
print("Date:", str(d))
print("Time:", str(t))
print("DateTime:", str(dt))
# Format codes reference
print("\nFormat codes:")
codes = [
("%Y", "4-digit year"),
("%y", "2-digit year"),
("%m", "2-digit month"),
("%B", "Full month name"),
("%b", "Short month name"),
("%d", "2-digit day"),
("%A", "Full day name"),
("%a", "Short day name"),
("%H", "24-hour (00-23)"),
("%I", "12-hour (01-12)"),
("%M", "Minute"),
("%S", "Second"),
("%p", "AM/PM")
]
for code, description in codes:
try:
value = dt.strftime(code)
print(f"{code}: {description} = {value}")
except:
pass
parse.py
# Parse from string
from datetime import datetime, date, time
# Parse datetime
# Parse ISO format
iso =
dt1 = datetime.fromisoformat(iso)
print("Parsed ISO:", dt1)
# Parse with custom pattern
custom1 = "29/01/2025 14:30"
dt2 = datetime.strptime(custom1, "%d/%m/%Y %H:%M")
print("Parsed", custom1, ":", dt2)
# Parse various formats
print("\nParse various formats:")
datetime_strings = [
("2025-01-29 14:30:45", "%Y-%m-%d %H:%M:%S"),
("01/29/2025 02:30 PM", "%m/%d/%Y %I:%M %p"),
("29-Jan-2025 14:30", "%d-%b-%Y %H:%M")
]
for dt_str, fmt in datetime_strings:
dt = datetime.strptime(dt_str, fmt)
print(f"{dt_str} -> {dt}")
# Parse dates
print("\nParse dates:")
date1 = date.fromisoformat("2025-01-29")
print("ISO date:", date1)
date2 = datetime.strptime("01/29/2025", "%m/%d/%Y").date()
print("US date:", date2)
# Parse times
print("\nParse times:")
time1 = time.fromisoformat("14:30:45")
print("ISO time:", time1)
time2 = datetime.strptime("02:30 PM", "%I:%M %p").time()
print("12-hour time:", time2)
# Handle parse errors
print("\nHandle parse errors:")
test_strings = [
"2025-01-29T14:30:45",
"2025-13-01T14:30:45", # invalid month
"not-a-datetime"
]
for s in test_strings:
try:
dt = datetime.fromisoformat(s)
print(f"{s} -> {dt}")
except ValueError:
print(f"{s} -> ERROR: Invalid format")
# Safe parse helper
def safe_parse_datetime(s, fmt=None):
"""Safely parse datetime string"""
try:
if fmt:
return datetime.strptime(s, fmt)
else:
return datetime.fromisoformat(s)
except ValueError:
print(f"Invalid datetime: {s}")
return None
# Test safe parse
print("\nSafe parse:")
print(safe_parse_datetime("2025-01-29T14:30:45"))
print(safe_parse_datetime("invalid"))
# Parse with multiple formats
print("\nTry multiple formats:")
def parse_flexible(s):
"""Try multiple common formats"""
formats = [
"%Y-%m-%d",
"%m/%d/%Y",
"%d-%b-%Y",
"%Y-%m-%d %H:%M:%S",
"%m/%d/%Y %I:%M %p"
]
for fmt in formats:
try:
return datetime.strptime(s, fmt)
except ValueError:
continue
# Try ISO format
try:
return datetime.fromisoformat(s)
except ValueError:
return None
test_dates = [
"2025-01-29",
"01/29/2025",
"29-Jan-2025",
"2025-01-29 14:30:45",
"01/29/2025 02:30 PM"
]
for s in test_dates:
result = parse_flexible(s)
if result:
print(f"{s} -> {result}")
else:
print(f"{s} -> Could not parse")
# Parse from string
from datetime import datetime, date, time
# Parse datetime
# Parse ISO format
iso =
dt1 = datetime.fromisoformat(iso)
print("Parsed ISO:", dt1)
# Parse with custom pattern
custom1 = "29/01/2025 14:30"
dt2 = datetime.strptime(custom1, "%d/%m/%Y %H:%M")
print("Parsed", custom1, ":", dt2)
# Parse various formats
print("\nParse various formats:")
datetime_strings = [
("2025-01-29 14:30:45", "%Y-%m-%d %H:%M:%S"),
("01/29/2025 02:30 PM", "%m/%d/%Y %I:%M %p"),
("29-Jan-2025 14:30", "%d-%b-%Y %H:%M")
]
for dt_str, fmt in datetime_strings:
dt = datetime.strptime(dt_str, fmt)
print(f"{dt_str} -> {dt}")
# Parse dates
print("\nParse dates:")
date1 = date.fromisoformat("2025-01-29")
print("ISO date:", date1)
date2 = datetime.strptime("01/29/2025", "%m/%d/%Y").date()
print("US date:", date2)
# Parse times
print("\nParse times:")
time1 = time.fromisoformat("14:30:45")
print("ISO time:", time1)
time2 = datetime.strptime("02:30 PM", "%I:%M %p").time()
print("12-hour time:", time2)
# Handle parse errors
print("\nHandle parse errors:")
test_strings = [
"2025-01-29T14:30:45",
"2025-13-01T14:30:45", # invalid month
"not-a-datetime"
]
for s in test_strings:
try:
dt = datetime.fromisoformat(s)
print(f"{s} -> {dt}")
except ValueError:
print(f"{s} -> ERROR: Invalid format")
# Safe parse helper
def safe_parse_datetime(s, fmt=None):
"""Safely parse datetime string"""
try:
if fmt:
return datetime.strptime(s, fmt)
else:
return datetime.fromisoformat(s)
except ValueError:
print(f"Invalid datetime: {s}")
return None
# Test safe parse
print("\nSafe parse:")
print(safe_parse_datetime("2025-01-29T14:30:45"))
print(safe_parse_datetime("invalid"))
# Parse with multiple formats
print("\nTry multiple formats:")
def parse_flexible(s):
"""Try multiple common formats"""
formats = [
"%Y-%m-%d",
"%m/%d/%Y",
"%d-%b-%Y",
"%Y-%m-%d %H:%M:%S",
"%m/%d/%Y %I:%M %p"
]
for fmt in formats:
try:
return datetime.strptime(s, fmt)
except ValueError:
continue
# Try ISO format
try:
return datetime.fromisoformat(s)
except ValueError:
return None
test_dates = [
"2025-01-29",
"01/29/2025",
"29-Jan-2025",
"2025-01-29 14:30:45",
"01/29/2025 02:30 PM"
]
for s in test_dates:
result = parse_flexible(s)
if result:
print(f"{s} -> {result}")
else:
print(f"{s} -> Could not parse")
# Parse from string
from datetime import datetime, date, time
# Parse datetime
# Parse ISO format
iso =
dt1 = datetime.fromisoformat(iso)
print("Parsed ISO:", dt1)
# Parse with custom pattern
custom1 = "29/01/2025 14:30"
dt2 = datetime.strptime(custom1, "%d/%m/%Y %H:%M")
print("Parsed", custom1, ":", dt2)
# Parse various formats
print("\nParse various formats:")
datetime_strings = [
("2025-01-29 14:30:45", "%Y-%m-%d %H:%M:%S"),
("01/29/2025 02:30 PM", "%m/%d/%Y %I:%M %p"),
("29-Jan-2025 14:30", "%d-%b-%Y %H:%M")
]
for dt_str, fmt in datetime_strings:
dt = datetime.strptime(dt_str, fmt)
print(f"{dt_str} -> {dt}")
# Parse dates
print("\nParse dates:")
date1 = date.fromisoformat("2025-01-29")
print("ISO date:", date1)
date2 = datetime.strptime("01/29/2025", "%m/%d/%Y").date()
print("US date:", date2)
# Parse times
print("\nParse times:")
time1 = time.fromisoformat("14:30:45")
print("ISO time:", time1)
time2 = datetime.strptime("02:30 PM", "%I:%M %p").time()
print("12-hour time:", time2)
# Handle parse errors
print("\nHandle parse errors:")
test_strings = [
"2025-01-29T14:30:45",
"2025-13-01T14:30:45", # invalid month
"not-a-datetime"
]
for s in test_strings:
try:
dt = datetime.fromisoformat(s)
print(f"{s} -> {dt}")
except ValueError:
print(f"{s} -> ERROR: Invalid format")
# Safe parse helper
def safe_parse_datetime(s, fmt=None):
"""Safely parse datetime string"""
try:
if fmt:
return datetime.strptime(s, fmt)
else:
return datetime.fromisoformat(s)
except ValueError:
print(f"Invalid datetime: {s}")
return None
# Test safe parse
print("\nSafe parse:")
print(safe_parse_datetime("2025-01-29T14:30:45"))
print(safe_parse_datetime("invalid"))
# Parse with multiple formats
print("\nTry multiple formats:")
def parse_flexible(s):
"""Try multiple common formats"""
formats = [
"%Y-%m-%d",
"%m/%d/%Y",
"%d-%b-%Y",
"%Y-%m-%d %H:%M:%S",
"%m/%d/%Y %I:%M %p"
]
for fmt in formats:
try:
return datetime.strptime(s, fmt)
except ValueError:
continue
# Try ISO format
try:
return datetime.fromisoformat(s)
except ValueError:
return None
test_dates = [
"2025-01-29",
"01/29/2025",
"29-Jan-2025",
"2025-01-29 14:30:45",
"01/29/2025 02:30 PM"
]
for s in test_dates:
result = parse_flexible(s)
if result:
print(f"{s} -> {result}")
else:
print(f"{s} -> Could not parse")
iso.py
# ISO format
from datetime import datetime, date, time, timezone
# ISO 8601 formats
dt = datetime(2025, 1, 29, 14, 30, 45)
d = dt.date()
t = dt.time()
# ISO date
print("ISO Date formats:")
print("isoformat():", d.isoformat())
print("ISO string:", str(d))
# ISO time
print("\nISO Time formats:")
print("isoformat():", t.isoformat())
print("ISO string:", str(t))
# ISO datetime
print("\nISO DateTime formats:")
print("isoformat():", dt.isoformat())
print("ISO with T:", dt.isoformat(sep='T'))
print("ISO with space:", dt.isoformat(sep=' '))
# With timezone
dt_utc = datetime.now(timezone.utc)
print("\nWith timezone:")
print("UTC datetime:", dt_utc.isoformat())
# With microseconds
dt_micro = datetime(2025, 1, 29, 14, 30, 45, 123456)
print("\nWith microseconds:")
print("Full precision:", dt_micro.isoformat())
print("Truncated:", dt_micro.isoformat(timespec='seconds'))
# Different time specifications
print("\nTime specifications:")
for spec in ['auto', 'hours', 'minutes', 'seconds', 'milliseconds', 'microseconds']:
print(f"{spec:15}: {dt_micro.isoformat(timespec=spec)}")
# Parse ISO formats
print("\nParse ISO formats:")
iso_date = "2025-01-29"
parsed_date = date.fromisoformat(iso_date)
print(f"Date: {iso_date} -> {parsed_date}")
iso_time = "14:30:45"
parsed_time = time.fromisoformat(iso_time)
print(f"Time: {iso_time} -> {parsed_time}")
iso_datetime = "2025-01-29T14:30:45"
parsed_dt = datetime.fromisoformat(iso_datetime)
print(f"DateTime: {iso_datetime} -> {parsed_dt}")
# Compact formats
print("\nCompact formats:")
compact = dt.strftime("%Y%m%d")
print("Date compact:", compact)
compact_time = dt.strftime("%Y%m%dT%H%M%S")
print("DateTime compact:", compact_time)
# ISO week date
print("\nISO week date:")
iso_calendar = d.isocalendar()
print(f"Year: {iso_calendar.year}")
print(f"Week: {iso_calendar.week}")
print(f"Weekday: {iso_calendar.weekday}")
print(f"ISO week: {iso_calendar.year}-W{iso_calendar.week:02d}-{iso_calendar.weekday}")
# Round-trip conversion
print("\nRound-trip:")
original = datetime.now()
iso_str = original.isoformat()
parsed = datetime.fromisoformat(iso_str)
print(f"Original: {original}")
print(f"ISO string: {iso_str}")
print(f"Parsed: {parsed}")
print(f"Equal: {original == parsed}")
# Different separators
print("\nDifferent separators:")
print("T separator:", dt.isoformat(sep='T'))
print("Space separator:", dt.isoformat(sep=' '))
print("Custom:", dt.strftime("%Y-%m-%d %H:%M:%S"))
locale_format.py
# Locale-specific formatting
from datetime import datetime
import locale
# Locale-specific formatting
dt = datetime(2025, 1, 29, 14, 30, 45)
print("DateTime:", dt)
print()
# Get current locale
print("Current locale:", locale.getlocale())
print()
# Default locale formatting
print("Default locale:")
print("%c (full):", dt.strftime("%c"))
print("%x (date):", dt.strftime("%x"))
print("%X (time):", dt.strftime("%X"))
# Different locale examples (may vary by system)
locales_to_try = [
('en_US.UTF-8', 'US English'),
('en_GB.UTF-8', 'UK English'),
('fr_FR.UTF-8', 'French'),
('de_DE.UTF-8', 'German')
]
print("\nLocale-specific formats:")
original_locale = locale.getlocale()
for loc, name in locales_to_try:
try:
locale.setlocale(locale.LC_TIME, loc)
print(f"\n{name} ({loc}):")
print(" Full:", dt.strftime("%c"))
print(" Date:", dt.strftime("%x"))
print(" Time:", dt.strftime("%X"))
print(" Month:", dt.strftime("%B"))
print(" Day:", dt.strftime("%A"))
except locale.Error:
print(f"\n{name}: locale not available")
# Restore original locale
try:
locale.setlocale(locale.LC_TIME, original_locale)
except:
locale.setlocale(locale.LC_TIME, '')
# Locale-aware format codes
print("\nLocale-aware codes:")
print("%c - Full datetime:", dt.strftime("%c"))
print("%x - Date:", dt.strftime("%x"))
print("%X - Time:", dt.strftime("%X"))
print("%B - Month name:", dt.strftime("%B"))
print("%b - Short month:", dt.strftime("%b"))
print("%A - Day name:", dt.strftime("%A"))
print("%a - Short day:", dt.strftime("%a"))
print("%p - AM/PM:", dt.strftime("%p"))
# Manual locale formatting
print("\nManual locale formatting:")
month_names = {
'en': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
'es': ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'],
'fr': ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov', 'Déc']
}
for lang, months in month_names.items():
month_name = months[dt.month - 1]
print(f"{lang}: {dt.day} {month_name} {dt.year}")
# Custom format function
def format_locale(dt, pattern, locale_name='en_US'):
"""Format datetime with specific locale"""
original = locale.getlocale()
try:
locale.setlocale(locale.LC_TIME, locale_name)
result = dt.strftime(pattern)
locale.setlocale(locale.LC_TIME, original)
return result
except locale.Error:
return dt.strftime(pattern) # fallback
print("\nCustom locale function:")
patterns = ["%B", "%A", "%c"]
for pattern in patterns:
formatted = format_locale(dt, pattern, 'en_US')
print(f"{pattern}: {formatted}")
strftime
Converting datetime objects to formatted strings with strftime()
strptime
Converting strings to datetime objects with strptime()
iso_format
Working with ISO 8601 standard format for dates and times
locale_format
Formatting dates according to regional conventions
Exercise: practical.py
Create log formatters, filename generators, and user-friendly date displays