Timezone Handling Guide¶
Comprehensive guide to working with timezones in Carbonic, including conversion, DST handling, and best practices.
Overview¶
Carbonic provides robust timezone support using Python's zoneinfo module with:
- Automatic UTC defaults for timezone-aware operations
- Seamless conversions between timezones
- DST handling with proper transitions
- Naive datetime support when needed
Creating Timezone-Aware DateTimes¶
Default Behavior¶
from carbonic import DateTime
# Defaults to UTC
dt = DateTime(2024, 1, 15, 14, 30)
print(dt) # 2024-01-15T14:30:00+00:00
# Explicit UTC
dt_utc = DateTime(2024, 1, 15, 14, 30, tz="UTC")
print(dt_utc) # 2024-01-15T14:30:00+00:00
Specific Timezones¶
from carbonic import DateTime
# Major timezones
dt_ny = DateTime(2024, 1, 15, 14, 30, tz="America/New_York")
dt_london = DateTime(2024, 1, 15, 14, 30, tz="Europe/London")
dt_tokyo = DateTime(2024, 1, 15, 14, 30, tz="Asia/Tokyo")
print(dt_ny) # 2024-01-15T14:30:00-05:00 (EST)
print(dt_london) # 2024-01-15T14:30:00+00:00 (GMT)
print(dt_tokyo) # 2024-01-15T14:30:00+09:00 (JST)
Current Time in Different Timezones¶
from carbonic import DateTime
# Current time in various timezones
utc_now = DateTime.now() # UTC
ny_now = DateTime.now("America/New_York") # New York time
paris_now = DateTime.now("Europe/Paris") # Paris time
sydney_now = DateTime.now("Australia/Sydney") # Sydney time
print(f"UTC: {utc_now}")
print(f"NY: {ny_now}")
print(f"Paris: {paris_now}")
print(f"Sydney: {sydney_now}")
Timezone Conversion¶
Basic Conversion¶
from carbonic import DateTime
# Start with UTC
utc_time = DateTime(2024, 1, 15, 14, 30, tz="UTC")
print(f"UTC: {utc_time}")
# Convert to different timezones
ny_time = utc_time.as_timezone("America/New_York")
london_time = utc_time.as_timezone("Europe/London")
tokyo_time = utc_time.as_timezone("Asia/Tokyo")
print(f"New York: {ny_time}") # 09:30 EST (UTC-5)
print(f"London: {london_time}") # 14:30 GMT (UTC+0)
print(f"Tokyo: {tokyo_time}") # 23:30 JST (UTC+9)
# All represent the same moment in time
assert utc_time == ny_time == london_time == tokyo_time
Round-Trip Conversion¶
from carbonic import DateTime
# Original time
original = DateTime(2024, 6, 15, 14, 30, tz="Europe/Warsaw")
print(f"Original: {original}")
# Convert to different timezone and back
converted = original.as_timezone("America/Los_Angeles")
back_to_original = converted.as_timezone("Europe/Warsaw")
print(f"Converted: {converted}")
print(f"Back: {back_to_original}")
# Should be identical
assert original == back_to_original
Converting to Naive¶
from carbonic import DateTime
# Timezone-aware datetime
aware_dt = DateTime(2024, 1, 15, 14, 30, tz="UTC")
# Convert to naive (removes timezone info, keeps local time)
naive_dt = aware_dt.as_timezone(None)
print(f"Aware: {aware_dt}") # 2024-01-15T14:30:00+00:00
print(f"Naive: {naive_dt}") # 2024-01-15T14:30:00
Daylight Saving Time (DST)¶
DST Transitions¶
from carbonic import DateTime
# Before DST starts (Winter time)
winter_time = DateTime(2024, 3, 9, 15, 0, tz="America/New_York") # EST
print(f"Winter: {winter_time}") # UTC-5
# After DST starts (Summer time)
summer_time = DateTime(2024, 3, 11, 15, 0, tz="America/New_York") # EDT
print(f"Summer: {summer_time}") # UTC-4
# Convert both to UTC to see the difference
winter_utc = winter_time.as_timezone("UTC")
summer_utc = summer_time.as_timezone("UTC")
print(f"Winter UTC: {winter_utc}") # 20:00 UTC
print(f"Summer UTC: {summer_utc}") # 19:00 UTC
DST-Safe Arithmetic¶
from carbonic import DateTime
# Day before DST starts
before_dst = DateTime(2024, 3, 9, 10, 0, tz="America/New_York")
# Add 24 hours - this handles DST transition correctly
after_24h = before_dst.add(hours=24)
print(f"24 hours later: {after_24h}")
# Add 1 day - this maintains the same local time
next_day = before_dst.add(days=1)
print(f"1 day later: {next_day}")
# They might be different due to DST!
print(f"Same time? {after_24h == next_day}")
Working with Naive DateTimes¶
Creating Naive DateTimes¶
from carbonic import DateTime
# Explicit naive datetime
naive_dt = DateTime(2024, 1, 15, 14, 30, tz=None)
print(f"Naive: {naive_dt}") # 2024-01-15T14:30:00 (no timezone)
# Check if datetime is naive
print(f"Is naive? {naive_dt.tzinfo is None}") # True
Converting Naive to Aware¶
from carbonic import DateTime
# Start with naive
naive_dt = DateTime(2024, 1, 15, 14, 30, tz=None)
# Cannot directly convert naive to aware - would be ambiguous
try:
aware_dt = naive_dt.as_timezone("UTC") # This will raise an error
except ValueError as e:
print(f"Error: {e}")
# Instead, create a new aware datetime
aware_dt = DateTime(
naive_dt.year, naive_dt.month, naive_dt.day,
naive_dt.hour, naive_dt.minute, naive_dt.second,
naive_dt.microsecond, tz="UTC"
)
print(f"Now aware: {aware_dt}")
Common Timezone Operations¶
Comparing Times Across Timezones¶
from carbonic import DateTime
# Same moment in different timezones
utc_meeting = DateTime(2024, 1, 15, 15, 0, tz="UTC")
ny_meeting = utc_meeting.as_timezone("America/New_York") # 10:00 EST
london_meeting = utc_meeting.as_timezone("Europe/London") # 15:00 GMT
# All comparisons work correctly
print(f"UTC == NY: {utc_meeting == ny_meeting}") # True
print(f"NY < London: {ny_meeting < london_meeting}") # False (same time)
print(f"Meeting times equal: {utc_meeting == ny_meeting == london_meeting}") # True
Finding Business Hours¶
from carbonic import DateTime
def is_business_hours(dt, timezone="America/New_York"):
"""Check if datetime falls within business hours (9 AM - 5 PM)."""
local_time = dt.as_timezone(timezone)
return 9 <= local_time.hour < 17 and local_time.to_date().is_weekday()
# Test with different times
utc_time = DateTime(2024, 1, 15, 14, 0, tz="UTC") # Monday 2 PM UTC
print(f"Business hours in NY: {is_business_hours(utc_time, 'America/New_York')}") # True (9 AM EST)
print(f"Business hours in Tokyo: {is_business_hours(utc_time, 'Asia/Tokyo')}") # False (11 PM JST)
Best Practices¶
Always Use Timezone-Aware DateTimes¶
from carbonic import DateTime
# ✅ Good: Explicit timezone
meeting_time = DateTime(2024, 1, 15, 14, 0, tz="UTC")
user_time = meeting_time.as_timezone("America/New_York")
# ❌ Avoid: Naive datetime for anything that will be shared
# naive_time = DateTime(2024, 1, 15, 14, 0, tz=None) # Ambiguous!
Store in UTC, Display in Local¶
from carbonic import DateTime
# Store everything in UTC
def store_event(event_data):
"""Store event with UTC timestamp."""
return {
**event_data,
'created_at': DateTime.now().to_iso_string(), # Always UTC
'scheduled_for': event_data['local_time'].as_timezone("UTC").to_iso_string()
}
# Display in user's timezone
def display_event(event_data, user_timezone="America/New_York"):
"""Display event in user's local timezone."""
utc_time = DateTime.parse(event_data['scheduled_for'])
local_time = utc_time.as_timezone(user_timezone)
return f"Event at {local_time.format('g:i A')} ({user_timezone})"
Handle Timezone Conversion Errors¶
from carbonic import DateTime
def safe_timezone_convert(dt, target_timezone):
"""Safely convert timezone with error handling."""
try:
return dt.as_timezone(target_timezone)
except ValueError as e:
print(f"Timezone conversion failed: {e}")
return dt # Return original if conversion fails
# Usage
dt = DateTime(2024, 1, 15, 14, 30, tz="UTC")
result = safe_timezone_convert(dt, "Invalid/Timezone") # Handles error gracefully
Common Timezones Reference¶
Major World Timezones¶
from carbonic import DateTime
utc_time = DateTime(2024, 1, 15, 12, 0, tz="UTC") # Noon UTC
major_timezones = {
"UTC": "UTC",
"New York": "America/New_York", # EST/EDT
"Los Angeles": "America/Los_Angeles", # PST/PDT
"London": "Europe/London", # GMT/BST
"Paris": "Europe/Paris", # CET/CEST
"Warsaw": "Europe/Warsaw", # CET/CEST
"Tokyo": "Asia/Tokyo", # JST
"Sydney": "Australia/Sydney", # AEST/AEDT
"Mumbai": "Asia/Kolkata", # IST
"Dubai": "Asia/Dubai", # GST
}
print("Noon UTC in major cities:")
for city, tz in major_timezones.items():
local_time = utc_time.as_timezone(tz)
print(f"{city:12}: {local_time.format('H:i (T)')}")
US Timezones¶
from carbonic import DateTime
us_timezones = {
"Eastern": "America/New_York",
"Central": "America/Chicago",
"Mountain": "America/Denver",
"Pacific": "America/Los_Angeles",
"Alaska": "America/Anchorage",
"Hawaii": "Pacific/Honolulu",
}
utc_time = DateTime(2024, 7, 15, 20, 0, tz="UTC") # 8 PM UTC in summer
print("8 PM UTC across US timezones:")
for zone_name, tz in us_timezones.items():
local_time = utc_time.as_timezone(tz)
print(f"{zone_name:8}: {local_time.format('g:i A')}")
See Also¶
- DateTime Guide - Complete DateTime operations
- Parsing & Formatting - Working with timezone strings
- API Reference - Complete timezone API
- Examples - Practical timezone examples