Extensions to the standard Python datetime module
—
Comprehensive timezone handling supporting UTC, fixed offsets, system local timezone, tzfile format, Windows registry timezones, iCalendar timezones, POSIX TZ strings, and advanced DST handling.
class tzutc(tzinfo):
"""
UTC timezone implementation (singleton).
Standard tzinfo methods:
- utcoffset(dt) -> timedelta(0)
- dst(dt) -> timedelta(0)
- tzname(dt) -> "UTC"
- fromutc(dt) -> datetime
- is_ambiguous(dt) -> False
"""
# Predefined UTC instance
UTC = tzutc()class tzoffset(tzinfo):
def __init__(self, name, offset):
"""
Fixed UTC offset timezone.
Parameters:
- name (str): Timezone name/description
- offset (timedelta): UTC offset
"""
def utcoffset(self, dt):
"""Return the fixed offset."""
def dst(self, dt):
"""Return timedelta(0) - no DST."""
def tzname(self, dt):
"""Return the timezone name."""Usage Examples:
from dateutil.tz import tzutc, tzoffset, UTC
from datetime import datetime, timedelta
# UTC timezone
utc_dt = datetime.now(UTC)
utc_dt2 = datetime.now(tzutc()) # Same as UTC
# Fixed offset timezones
eastern_std = tzoffset("EST", timedelta(hours=-5))
india_std = tzoffset("IST", timedelta(hours=5, minutes=30))
dt_est = datetime(2023, 12, 25, 12, 0, tzinfo=eastern_std)
dt_ist = datetime(2023, 12, 25, 12, 0, tzinfo=india_std)class tzlocal(tzinfo):
"""
System local timezone with automatic DST handling.
Automatically detects system timezone and handles DST transitions.
"""
def utcoffset(self, dt):
"""Return system UTC offset for given datetime."""
def dst(self, dt):
"""Return DST offset for given datetime."""
def tzname(self, dt):
"""Return system timezone name."""Usage Examples:
from dateutil.tz import tzlocal
from datetime import datetime
local_tz = tzlocal()
local_time = datetime.now(local_tz)
print(f"Local time: {local_time}")
print(f"UTC offset: {local_tz.utcoffset(local_time)}")
print(f"DST offset: {local_tz.dst(local_time)}")class tzfile(tzinfo):
def __init__(self, fileobj, filename=None):
"""
Timezone from tzfile format (e.g., /usr/share/zoneinfo files).
Parameters:
- fileobj: File-like object with tzfile data
- filename (str, optional): Filename for reference
"""
def is_ambiguous(self, dt):
"""
Check if datetime is ambiguous during DST transition.
Returns:
bool: True if datetime occurs twice due to DST transition
"""
def fromutc(self, dt):
"""Convert UTC datetime to local timezone."""Usage Examples:
from dateutil.tz import tzfile
from datetime import datetime
# Load timezone from system file
with open('/usr/share/zoneinfo/America/New_York', 'rb') as f:
ny_tz = tzfile(f, 'America/New_York')
dt = datetime(2023, 12, 25, 12, 0, tzinfo=ny_tz)
print(f"Time in NY: {dt}")
print(f"Is ambiguous: {ny_tz.is_ambiguous(dt)}")class tzrange(tzinfo):
def __init__(self, stdabbr, stdoffset=None, dstabbr=None, dstoffset=None,
start=None, end=None):
"""
Timezone with explicit DST rules.
Parameters:
- stdabbr (str): Standard time abbreviation
- stdoffset (timedelta, optional): Standard time UTC offset
- dstabbr (str, optional): DST abbreviation
- dstoffset (timedelta, optional): DST UTC offset
- start (relativedelta, optional): DST start rule
- end (relativedelta, optional): DST end rule
"""class tzstr(tzrange):
def __init__(self, s, posix=True):
"""
Parse timezone from POSIX TZ environment string.
Parameters:
- s (str): TZ string (e.g., "EST5EDT,M3.2.0,M11.1.0")
- posix (bool): Use POSIX-style parsing
"""Usage Examples:
from dateutil.tz import tzstr
from datetime import datetime
# Parse POSIX TZ strings
eastern = tzstr("EST5EDT,M3.2.0,M11.1.0") # US Eastern
pacific = tzstr("PST8PDT,M3.2.0,M11.1.0") # US Pacific
dt = datetime(2023, 7, 15, 12, 0, tzinfo=eastern)
print(f"Eastern time: {dt}")
print(f"Pacific time: {dt.astimezone(pacific)}")class tzical:
def __init__(self, fileobj):
"""
Parse timezones from iCalendar (.ics) files.
Parameters:
- fileobj: File-like object with iCalendar data
"""
def get(self, name=None):
"""
Get timezone by name.
Parameters:
- name (str, optional): Timezone name, or None for default
Returns:
tzinfo: Timezone object
"""
def keys(self):
"""
Get list of available timezone names.
Returns:
list[str]: Available timezone names
"""def gettz(name=None):
"""
Get timezone by name with intelligent fallback.
Parameters:
- name (str, optional): Timezone name or None for local timezone
Returns:
tzinfo: Appropriate timezone object
Resolution order:
1. System zoneinfo if available (preferred)
2. dateutil bundled zoneinfo
3. Fixed offset if name looks like offset
4. Local timezone if name is None
5. None if unable to resolve
"""Usage Examples:
from dateutil.tz import gettz
from datetime import datetime
# Get various timezones
utc = gettz('UTC')
local = gettz() # System local timezone
ny = gettz('America/New_York')
tokyo = gettz('Asia/Tokyo')
london = gettz('Europe/London')
# Fixed offset styles
plus5 = gettz('+05:00')
minus8 = gettz('-0800')
# Create timezone-aware datetime
dt = datetime(2023, 12, 25, 12, 0, tzinfo=ny)
tokyo_time = dt.astimezone(tokyo)def enfold(dt, fold=1):
"""
Set fold attribute for ambiguous times during DST transitions.
Parameters:
- dt (datetime): Datetime to modify
- fold (int): Fold value (0 or 1)
Returns:
datetime: Datetime with fold attribute set
"""
def datetime_ambiguous(dt, tz=None):
"""
Check if datetime is ambiguous in timezone.
Parameters:
- dt (datetime): Datetime to check
- tz (tzinfo, optional): Timezone, uses dt.tzinfo if None
Returns:
bool: True if datetime is ambiguous
"""
def datetime_exists(dt, tz=None):
"""
Check if datetime exists in timezone.
Parameters:
- dt (datetime): Datetime to check
- tz (tzinfo, optional): Timezone, uses dt.tzinfo if None
Returns:
bool: True if datetime exists (not in DST gap)
"""
def resolve_imaginary(dt):
"""
Resolve non-existent times during DST transitions.
Parameters:
- dt (datetime): Potentially non-existent datetime
Returns:
datetime: Resolved datetime
"""Usage Examples:
from dateutil.tz import gettz, enfold, datetime_ambiguous, datetime_exists, resolve_imaginary
from datetime import datetime
eastern = gettz('America/New_York')
# DST transition handling
# Fall back: 2023-11-05 01:30 occurs twice
ambiguous_time = datetime(2023, 11, 5, 1, 30, tzinfo=eastern)
print(f"Is ambiguous: {datetime_ambiguous(ambiguous_time)}")
# Specify which occurrence using fold
first_occurrence = enfold(ambiguous_time, fold=0)
second_occurrence = enfold(ambiguous_time, fold=1)
# Spring forward: 2023-03-12 02:30 doesn't exist
nonexistent_time = datetime(2023, 3, 12, 2, 30, tzinfo=eastern)
print(f"Exists: {datetime_exists(nonexistent_time)}")
# Resolve the gap
resolved_time = resolve_imaginary(nonexistent_time)
print(f"Resolved to: {resolved_time}")# Available only on Windows
class tzwin(tzinfo):
"""Windows registry-based timezone."""
class tzwinlocal(tzinfo):
"""Windows local timezone from registry."""from dateutil.tz import gettz
from datetime import datetime
# Create timezone-aware datetime
utc = gettz('UTC')
dt_utc = datetime(2023, 12, 25, 17, 0, tzinfo=utc)
# Convert through multiple timezones
timezones = ['America/New_York', 'Europe/London', 'Asia/Tokyo', 'Australia/Sydney']
converted_times = {}
for tz_name in timezones:
tz = gettz(tz_name)
converted_times[tz_name] = dt_utc.astimezone(tz)
for tz_name, dt in converted_times.items():
print(f"{tz_name}: {dt}")from dateutil.tz import gettz
from datetime import datetime, time
def is_business_hours(dt, timezone_name):
"""Check if datetime is during business hours in given timezone."""
tz = gettz(timezone_name)
local_dt = dt.astimezone(tz)
# Business hours: 9 AM - 5 PM, Monday-Friday
if local_dt.weekday() >= 5: # Weekend
return False
business_start = time(9, 0)
business_end = time(17, 0)
return business_start <= local_dt.time() <= business_end
# Test across multiple timezones
utc_time = datetime(2023, 12, 25, 14, 0, tzinfo=gettz('UTC'))
timezones = ['America/New_York', 'Europe/London', 'Asia/Tokyo']
for tz in timezones:
in_hours = is_business_hours(utc_time, tz)
print(f"{tz}: {'Open' if in_hours else 'Closed'}")from dateutil.tz import gettz, datetime_exists, resolve_imaginary
from datetime import datetime, timedelta
def safe_add_time(dt, delta):
"""Add time duration while handling DST transitions safely."""
result = dt + delta
if not datetime_exists(result):
result = resolve_imaginary(result)
return result
# Example: Add 24 hours during DST transition
eastern = gettz('America/New_York')
before_transition = datetime(2023, 3, 11, 12, 0, tzinfo=eastern)
# Naive addition might hit DST gap
safe_result = safe_add_time(before_transition, timedelta(hours=24))
print(f"Safe result: {safe_result}")class DeprecatedTzFormatWarning(Warning):
"""Warning raised when parsing deprecated timezone formats."""from datetime import datetime, timedelta, tzinfo
# Core timezone classes inherit from tzinfo
class tzutc(tzinfo): ...
class tzoffset(tzinfo): ...
class tzlocal(tzinfo): ...
class tzfile(tzinfo): ...
class tzrange(tzinfo): ...
class tzstr(tzrange): ...
# Platform-specific (Windows only)
class tzwin(tzinfo): ...
class tzwinlocal(tzinfo): ...
# iCalendar timezone container
class tzical:
def get(self, name=None) -> tzinfo: ...
def keys(self) -> list[str]: ...
# Utility function return types
TzInfo = tzinfo | NoneInstall with Tessl CLI
npx tessl i tessl/pypi-python-dateutil