Implementation:Apache Airflow Timezone Utilities
Appearance
| Knowledge Sources | |
|---|---|
| Domains | Core_Infrastructure, Datetime_Handling |
| Last Updated | 2026-02-08 21:00 GMT |
Overview
Timezone utility module providing functions for creating, converting, formatting, and parsing timezone-aware datetimes using Pendulum, with transparent compatibility across Pendulum 2 and Pendulum 3 versions.
Description
The timezone module is a foundational utility used throughout Airflow to ensure all datetime values are timezone-aware. It wraps the Pendulum library and provides a consistent API that works across both Pendulum 2 and Pendulum 3.
Key design aspects:
- Initialized timezone: A module-level
_Timezoneclass tracks the configured default timezone (set viainitialize()at Airflow startup). All functions that need a timezone default to this initialized value rather than requiring it as a parameter. - Pendulum version detection: The
_PENDULUM3boolean flag is computed at import time from the installed Pendulum version. Functions likeparse_timezone()andlocal_timezone()use this flag to call the correct Pendulum API. - Naive/aware enforcement: Functions like
make_aware()andmake_naive()include runtime checks to prevent accidental double-conversion. - UTC constant: The
utcmodule-level constant is set topendulum.UTCfor convenient access.
Usage
from airflow_shared.timezones.timezone import utcnow, convert_to_utc, make_aware, parse
# Get current UTC time
now = utcnow()
# Convert a naive datetime to UTC
import datetime as dt
naive_dt = dt.datetime(2024, 6, 15, 10, 30, 0)
utc_dt = convert_to_utc(make_aware(naive_dt))
# Parse a time string
parsed = parse("2024-06-15T10:30:00+02:00")
Code Reference
Source Location
- Repository: Apache_Airflow
- File:
shared/timezones/src/airflow_shared/timezones/timezone.py
Constants
utc = pendulum.UTC
# UTC Timezone as a tzinfo instance. Actual value depends on pendulum version:
# - Timezone("UTC") in pendulum 3
# - FixedTimezone(0, "UTC") in pendulum 2
_PENDULUM3 = version.parse(metadata.version("pendulum")).major == 3
Key Functions
Awareness Checks
def is_localized(value: dt.datetime) -> bool:
"""Determine if a given datetime.datetime is aware."""
def is_naive(value) -> bool:
"""Determine if a given datetime.datetime is naive."""
Time Creation
def utcnow() -> dt.datetime:
"""Get the current date and time in UTC."""
def datetime(*args, **kwargs) -> dt.datetime:
"""Wrap around datetime.datetime to add the initialized timezone if tzinfo not specified."""
def from_timestamp(timestamp: int | float, tz: str | FixedTimezone | Timezone = utc) -> DateTime:
"""Parse timestamp and return DateTime in a given time zone."""
Conversion
def convert_to_utc(value: dt.datetime | None) -> DateTime | None:
"""Create a datetime with the default timezone added if none is associated,
then convert to UTC."""
def make_aware(value: dt.datetime | None, timezone: dt.tzinfo | None = None) -> dt.datetime | None:
"""Make a naive datetime.datetime in a given time zone aware."""
def make_naive(value, timezone=None):
"""Make an aware datetime.datetime naive in a given time zone."""
def coerce_datetime(v: dt.datetime | None, tz: dt.tzinfo | None = None) -> DateTime | None:
"""Convert v into a timezone-aware pendulum.DateTime."""
Parsing
def parse(string: str, timezone=None, *, strict=False) -> DateTime:
"""Parse a time string and return an aware datetime."""
def parse_timezone(name: str | int) -> FixedTimezone | Timezone:
"""Parse timezone and return one of the pendulum Timezone objects.
Handles Pendulum 2/3 API differences transparently."""
Formatting
def td_format(td_object: None | dt.timedelta | float | int) -> str | None:
"""Format a timedelta object or float/int into a readable string.
Example: timedelta(seconds=3752) -> '1h:2M:32s'
Returns '<1s' for sub-second durations."""
Initialization
def initialize(default_timezone: str) -> None:
"""Initialize the default timezone for the timezone library.
Called automatically by airflow-core and task-sdk during startup.
Pass 'system' to use the local system timezone."""
def local_timezone() -> FixedTimezone | Timezone:
"""Return the local timezone."""
Import
from airflow_shared.timezones.timezone import utcnow, convert_to_utc, make_aware, parse
from airflow_shared.timezones.timezone import (
utc, is_localized, is_naive, make_naive,
coerce_datetime, td_format, parse_timezone,
local_timezone, initialize, from_timestamp,
)
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| value | datetime.datetime or None | Yes (varies) | The datetime to convert, check, or format |
| timezone | dt.tzinfo or None | No | Target timezone; defaults to the initialized timezone |
| string | str | Yes (for parse) | A date/time string in ISO 8601 or other parseable format |
| timestamp | int or float | Yes (for from_timestamp) | Epoch time in seconds |
| default_timezone | str | Yes (for initialize) | IANA timezone string or "system"
|
| td_object | timedelta, float, int, or None | Yes (for td_format) | Duration to format |
Outputs
| Name | Type | Description |
|---|---|---|
| Aware datetime | pendulum.DateTime or dt.datetime | Timezone-aware datetime object |
| Naive datetime | dt.datetime | Datetime with tzinfo stripped |
| Boolean | bool | Result of is_localized() or is_naive()
|
| Formatted string | str or None | Human-readable duration (e.g., "1h:2M:32s") or None
|
| Timezone | FixedTimezone or Timezone | Parsed Pendulum timezone object |
Usage Examples
Timezone Initialization at Startup
from airflow_shared.timezones.timezone import initialize
# Use UTC as the default timezone
initialize("UTC")
# Or use a specific timezone
initialize("America/New_York")
# Or use the system's local timezone
initialize("system")
Working with Task Schedules
from airflow_shared.timezones.timezone import utcnow, convert_to_utc, make_aware, parse
import datetime as dt
# Record when a task started
start_time = utcnow()
# Convert a user-provided naive datetime to UTC
user_input = dt.datetime(2024, 12, 25, 8, 0, 0)
utc_time = convert_to_utc(make_aware(user_input))
# Parse a schedule string
next_run = parse("2024-12-25T08:00:00", timezone="US/Eastern")
Formatting Task Durations
from airflow_shared.timezones.timezone import td_format
import datetime as dt
duration = dt.timedelta(hours=2, minutes=15, seconds=42)
print(td_format(duration)) # "2h:15M:42s"
short_duration = dt.timedelta(milliseconds=500)
print(td_format(short_duration)) # "<1s"
# Also works with raw seconds
print(td_format(7384)) # "2h:3M:4s"
Pendulum 2/3 Compatibility
from airflow_shared.timezones.timezone import parse_timezone, local_timezone
# Works regardless of installed Pendulum version
eastern = parse_timezone("US/Eastern")
local = local_timezone()
Related Pages
Page Connections
Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment