Extensions to the standard Python datetime module
—
Access to dateutil's bundled timezone database with metadata support, providing an alternative to system timezone data. Includes both modern and deprecated interfaces.
class ZoneInfoFile:
def __init__(self, zonefile_stream=None):
"""
Interface to timezone database from tarball stream.
Parameters:
- zonefile_stream (file-like, optional): Stream containing zoneinfo tarball data
If None, creates empty ZoneInfoFile
"""
def get(self, name, default=None):
"""
Get timezone by name from the database.
Parameters:
- name (str): IANA timezone name (e.g., 'America/New_York')
- default: Value to return if timezone not found
Returns:
tzfile | default: Timezone object or default value
"""
# Attributes
zones: dict[str, tzfile] # Dictionary mapping timezone names to tzfile objects
metadata: dict | None # Database metadata (version, build info, etc.)Usage Examples:
from dateutil.zoneinfo import ZoneInfoFile, get_zonefile_instance
from datetime import datetime
# Use the default instance (recommended)
zif = get_zonefile_instance()
# Get specific timezone
ny_tz = zif.get('America/New_York')
if ny_tz:
dt = datetime(2023, 12, 25, 12, 0, tzinfo=ny_tz)
print(f"Time in NY: {dt}")
# Handle missing timezone gracefully
unknown_tz = zif.get('Invalid/Timezone', default=None)
if unknown_tz is None:
print("Timezone not found")
# Explore available timezones
print(f"Available timezones: {len(zif.zones)}")
print(f"Sample timezones: {list(zif.zones.keys())[:10]}")
# Check metadata
if zif.metadata:
print(f"Database version: {zif.metadata.get('version', 'unknown')}")def get_zonefile_instance(new_instance=False):
"""
Get cached or new ZoneInfoFile instance using dateutil's bundled data.
Parameters:
- new_instance (bool): If True, create and cache new instance
If False, return existing cached instance
Returns:
ZoneInfoFile: Timezone database instance
"""Usage Examples:
from dateutil.zoneinfo import get_zonefile_instance
# Get default cached instance (efficient for repeated use)
zif1 = get_zonefile_instance()
zif2 = get_zonefile_instance()
print(f"Same instance: {zif1 is zif2}") # True
# Force new instance creation
zif_new = get_zonefile_instance(new_instance=True)
print(f"New instance: {zif1 is zif_new}") # False
# Subsequent calls return the new cached instance
zif3 = get_zonefile_instance()
print(f"Uses new cache: {zif3 is zif_new}") # Truedef getzoneinfofile_stream():
"""
Get the raw zoneinfo tarball data as a stream.
Returns:
BytesIO | None: Stream containing dateutil's bundled zoneinfo tarball data,
or None if file cannot be read
Warning:
Internal function - prefer using get_zonefile_instance() for normal usage
"""Usage Examples:
from dateutil.zoneinfo import getzoneinfofile_stream, ZoneInfoFile
# Get raw zoneinfo stream (advanced usage)
stream = getzoneinfofile_stream()
if stream:
# Create custom ZoneInfoFile instance
custom_zif = ZoneInfoFile(stream)
print(f"Loaded {len(custom_zif.zones)} timezones")
else:
print("Could not access zoneinfo data")from dateutil.zoneinfo import ZoneInfoFile
from io import BytesIO
# Load from custom tarball data (advanced usage)
with open('custom-zoneinfo.tar.gz', 'rb') as f:
custom_zif = ZoneInfoFile(f)
# Use custom timezone data
custom_tz = custom_zif.get('Custom/Timezone')
print(f"Custom zones available: {len(custom_zif.zones)}")Warning: The following functions are deprecated as of dateutil 2.6 and will be removed in future versions. Use ZoneInfoFile class instead.
def gettz(name):
"""
Get timezone from dateutil's bundled zoneinfo tarball.
DEPRECATED: Use get_zonefile_instance().get(name) instead.
Parameters:
- name (str): IANA timezone name
Returns:
tzfile | None: Timezone object or None if not found
Warnings:
DeprecationWarning: This function will be removed in future versions
"""
def gettz_db_metadata():
"""
Get zoneinfo database metadata.
DEPRECATED: Use get_zonefile_instance().metadata instead.
Returns:
dict | None: Database metadata dictionary
Warnings:
DeprecationWarning: This function will be removed in future versions
"""Migration Examples:
# OLD (deprecated) - will show deprecation warnings
from dateutil.zoneinfo import gettz, gettz_db_metadata
old_tz = gettz('America/New_York') # DeprecationWarning
old_metadata = gettz_db_metadata() # DeprecationWarning
# NEW (recommended) - no warnings
from dateutil.zoneinfo import get_zonefile_instance
zif = get_zonefile_instance()
new_tz = zif.get('America/New_York')
new_metadata = zif.metadatafrom dateutil.zoneinfo import get_zonefile_instance
import json
def explore_timezone_database():
"""Explore the contents of the timezone database."""
zif = get_zonefile_instance()
# Basic statistics
total_zones = len(zif.zones)
print(f"Total timezone entries: {total_zones}")
# Group by continent
continents = {}
for zone_name in zif.zones.keys():
if '/' in zone_name:
continent = zone_name.split('/')[0]
continents[continent] = continents.get(continent, 0) + 1
print("\nTimezones by continent:")
for continent, count in sorted(continents.items()):
print(f" {continent}: {count}")
# Show metadata
if zif.metadata:
print(f"\nDatabase metadata:")
print(json.dumps(zif.metadata, indent=2))
return {
'total_zones': total_zones,
'continents': continents,
'metadata': zif.metadata
}
# Run exploration
db_info = explore_timezone_database()from dateutil.zoneinfo import get_zonefile_instance
from dateutil.tz import gettz
def validate_timezone_name(tz_name):
"""
Validate timezone name against multiple sources.
Returns dict with validation results from different sources.
"""
results = {
'system_tz': None,
'dateutil_bundled': None,
'is_valid': False
}
# Check system timezone
system_tz = gettz(tz_name)
results['system_tz'] = system_tz is not None
# Check dateutil bundled data
zif = get_zonefile_instance()
bundled_tz = zif.get(tz_name)
results['dateutil_bundled'] = bundled_tz is not None
# Overall validity
results['is_valid'] = results['system_tz'] or results['dateutil_bundled']
return results
# Test various timezone names
test_timezones = [
'America/New_York',
'Europe/London',
'Invalid/Timezone',
'UTC',
'US/Eastern' # Legacy name
]
for tz_name in test_timezones:
validation = validate_timezone_name(tz_name)
print(f"{tz_name}: {validation}")from dateutil.zoneinfo import get_zonefile_instance, gettz
from dateutil.tz import gettz as tz_gettz
import time
def benchmark_timezone_access():
"""Compare performance of different timezone access methods."""
timezone_names = [
'America/New_York', 'Europe/London', 'Asia/Tokyo',
'America/Los_Angeles', 'Europe/Paris', 'Asia/Shanghai'
]
# Benchmark system gettz
start = time.time()
for name in timezone_names * 100:
tz = tz_gettz(name)
system_time = time.time() - start
# Benchmark ZoneInfoFile (single instance)
zif = get_zonefile_instance()
start = time.time()
for name in timezone_names * 100:
tz = zif.get(name)
bundled_time = time.time() - start
# Benchmark deprecated gettz (with warnings suppressed)
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore")
start = time.time()
for name in timezone_names * 100:
tz = gettz(name) # Deprecated function
deprecated_time = time.time() - start
print("Timezone access performance (600 lookups):")
print(f"System gettz(): {system_time:.4f}s")
print(f"ZoneInfoFile.get(): {bundled_time:.4f}s")
print(f"Deprecated gettz(): {deprecated_time:.4f}s")
benchmark_timezone_access()from dateutil.zoneinfo import get_zonefile_instance
from dateutil.tz import gettz
from datetime import datetime
def compare_timezone_implementations(tz_name, test_datetime):
"""Compare system vs bundled timezone implementations."""
# Get timezone from both sources
system_tz = gettz(tz_name)
zif = get_zonefile_instance()
bundled_tz = zif.get(tz_name)
if not system_tz or not bundled_tz:
return f"Timezone {tz_name} not available in one or both sources"
# Create datetime with each timezone
system_dt = test_datetime.replace(tzinfo=system_tz)
bundled_dt = test_datetime.replace(tzinfo=bundled_tz)
# Compare properties
comparison = {
'timezone_name': tz_name,
'test_datetime': test_datetime,
'system': {
'utc_offset': system_tz.utcoffset(test_datetime),
'dst_offset': system_tz.dst(test_datetime),
'tzname': system_tz.tzname(test_datetime)
},
'bundled': {
'utc_offset': bundled_tz.utcoffset(test_datetime),
'dst_offset': bundled_tz.dst(test_datetime),
'tzname': bundled_tz.tzname(test_datetime)
}
}
# Check for differences
comparison['differences'] = []
for prop in ['utc_offset', 'dst_offset', 'tzname']:
if comparison['system'][prop] != comparison['bundled'][prop]:
comparison['differences'].append(prop)
return comparison
# Test with specific datetime
test_dt = datetime(2023, 7, 15, 12, 0) # Summer time
result = compare_timezone_implementations('America/New_York', test_dt)
print(f"Comparison results: {result}")ZONEFILENAME = "dateutil-zoneinfo.tar.gz" # Default zoneinfo tarball filename
METADATA_FN = 'METADATA' # Metadata filename within tarballfrom dateutil.tz import tzfile
from typing import BinaryIO
class ZoneInfoFile:
zones: dict[str, tzfile]
metadata: dict | None
def get(self, name: str, default=None) -> tzfile | None: ...
# Function return types
ZoneInfoInstance = ZoneInfoFile
TzFileResult = tzfile | None
MetadataResult = dict | None
# File stream types for custom loading
ZoneInfoStream = BinaryIO | NoneInstall with Tessl CLI
npx tessl i tessl/pypi-python-dateutil