Claude Code for zoneinfo: Python IANA Timezone Database — Claude Skills 360 Blog
Blog / AI / Claude Code for zoneinfo: Python IANA Timezone Database
AI

Claude Code for zoneinfo: Python IANA Timezone Database

Published: December 27, 2028
Read time: 5 min read
By: Claude Skills 360

Python’s zoneinfo module (Python 3.9+) provides access to the IANA timezone database for creating fully-aware datetime objects. from zoneinfo import ZoneInfo. Create: tz = ZoneInfo("America/New_York") — wraps the IANA key and implements the tzinfo interface. Attach: dt = datetime(2024, 6, 15, 9, 0, tzinfo=ZoneInfo("Europe/London")). Convert: dt.astimezone(ZoneInfo("Asia/Tokyo")). List all zones: zoneinfo.available_timezones()set[str] (system-dependent). UTC shortcut: ZoneInfo("UTC"). Cache control: ZoneInfo.no_cache("America/Los_Angeles") → bypasses the module cache; ZoneInfo.clear_cache() — flush all cached instances. Error: ZoneInfoNotFoundError (subclass of KeyError) raised when the timezone key doesn’t exist. Fallback data: install tzdata (PyPI) to bundle timezone data on systems without /usr/share/zoneinfo (e.g. Windows, some Docker images). Claude Code generates timezone-aware scheduling systems, UTC converters, local time helpers, DST-safe arithmetic, and multi-region calendar tools.

CLAUDE.md for zoneinfo

## zoneinfo Stack
- Stdlib: from zoneinfo import ZoneInfo, available_timezones, ZoneInfoNotFoundError
- Create: tz = ZoneInfo("America/New_York")
- Aware:  dt = datetime(2024, 6, 15, 9, 0, tzinfo=ZoneInfo("UTC"))
- Convert: dt_local = dt.astimezone(ZoneInfo("Europe/Berlin"))
- List:   available_timezones()  # set of IANA keys
- Fallback: pip install tzdata   # for Windows / minimal containers
- Note:   Python 3.9+; backports.zoneinfo for 3.6–3.8

zoneinfo Timezone Pipeline

# app/zoneinfoutil.py — conversion, schedule, DST guard, multi-region, summary
from __future__ import annotations

import datetime
from dataclasses import dataclass, field
from typing import Any

try:
    from zoneinfo import ZoneInfo, ZoneInfoNotFoundError, available_timezones
except ImportError:  # Python < 3.9
    from backports.zoneinfo import ZoneInfo, ZoneInfoNotFoundError, available_timezones  # type: ignore


# ─────────────────────────────────────────────────────────────────────────────
# 1. Timezone lookup helpers
# ─────────────────────────────────────────────────────────────────────────────

def get_tz(key: str) -> "ZoneInfo | None":
    """
    Return a ZoneInfo for key, or None if the key is not found.

    Example:
        tz = get_tz("America/Chicago")
        tz_bad = get_tz("Not/AZone")   # None
    """
    try:
        return ZoneInfo(key)
    except (ZoneInfoNotFoundError, KeyError):
        return None


def tz_or_utc(key: "str | None") -> ZoneInfo:
    """
    Return ZoneInfo for key, falling back to UTC on error or None.

    Example:
        tz = tz_or_utc("Europe/Paris")
        tz = tz_or_utc(None)           # ZoneInfo("UTC")
    """
    if key:
        tz = get_tz(key)
        if tz is not None:
            return tz
    return ZoneInfo("UTC")


def search_timezones(substring: str) -> list[str]:
    """
    Return IANA timezone keys that contain substring (case-insensitive).

    Example:
        search_timezones("london")      # ["Europe/London"]
        search_timezones("us/")         # ["US/Eastern", "US/Pacific", ...]
    """
    lower = substring.lower()
    return sorted(k for k in available_timezones() if lower in k.lower())


def list_region_zones(region: str) -> list[str]:
    """
    Return all IANA keys for a top-level region prefix (e.g. "America", "Europe").

    Example:
        list_region_zones("Pacific")   # ["Pacific/Auckland", ...]
    """
    prefix = region.rstrip("/") + "/"
    return sorted(k for k in available_timezones() if k.startswith(prefix))


# ─────────────────────────────────────────────────────────────────────────────
# 2. Datetime conversion utilities
# ─────────────────────────────────────────────────────────────────────────────

def now_in(tz_key: str) -> datetime.datetime:
    """
    Return the current time in the given timezone.

    Example:
        print(now_in("Asia/Tokyo"))
        print(now_in("UTC"))
    """
    return datetime.datetime.now(tz=ZoneInfo(tz_key))


def utc_now() -> datetime.datetime:
    """Return the current UTC time as a timezone-aware datetime."""
    return datetime.datetime.now(tz=ZoneInfo("UTC"))


def to_utc(dt: datetime.datetime) -> datetime.datetime:
    """
    Convert a timezone-aware datetime to UTC.
    Naive datetimes are assumed to be in UTC.

    Example:
        local = datetime.datetime(2024, 6, 1, 12, 0, tzinfo=ZoneInfo("US/Eastern"))
        print(to_utc(local))   # 2024-06-01 16:00:00+00:00
    """
    if dt.tzinfo is None:
        return dt.replace(tzinfo=ZoneInfo("UTC"))
    return dt.astimezone(ZoneInfo("UTC"))


def convert_tz(dt: datetime.datetime, target_key: str) -> datetime.datetime:
    """
    Convert a timezone-aware datetime to a different timezone.
    Naive datetimes are treated as UTC.

    Example:
        utc_dt = datetime.datetime(2024, 1, 15, 18, 0, tzinfo=ZoneInfo("UTC"))
        ny_dt = convert_tz(utc_dt, "America/New_York")
        print(ny_dt)   # 2024-01-15 13:00:00-05:00
    """
    if dt.tzinfo is None:
        dt = dt.replace(tzinfo=ZoneInfo("UTC"))
    return dt.astimezone(ZoneInfo(target_key))


def localize_naive(dt: datetime.datetime, tz_key: str) -> datetime.datetime:
    """
    Attach a timezone to a naive datetime (replaces tzinfo without conversion).
    Use this when you know the datetime represents local time in tz_key.

    Example:
        naive = datetime.datetime(2024, 3, 10, 2, 30)   # ambiguous in US/Eastern DST
        aware = localize_naive(naive, "America/New_York")
    """
    return dt.replace(tzinfo=ZoneInfo(tz_key))


# ─────────────────────────────────────────────────────────────────────────────
# 3. DST / UTC-offset inspection
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class TzStatus:
    """
    Snapshot of timezone state at a given moment.

    Example:
        s = tz_status_at(datetime.datetime(2024, 7, 4, tzinfo=ZoneInfo("UTC")), "America/New_York")
        print(s.abbr, s.utcoffset, s.is_dst)
    """
    key:       str
    utcoffset: datetime.timedelta
    abbr:      str
    is_dst:    bool

    def offset_hours(self) -> float:
        return self.utcoffset.total_seconds() / 3600


def tz_status_at(dt: datetime.datetime, tz_key: str) -> TzStatus:
    """
    Return timezone status (offset, abbreviation, DST flag) at a given UTC moment.

    Example:
        summer = datetime.datetime(2024, 7, 1, 12, tzinfo=ZoneInfo("UTC"))
        winter = datetime.datetime(2024, 1, 1, 12, tzinfo=ZoneInfo("UTC"))
        print(tz_status_at(summer, "America/Los_Angeles").abbr)   # PDT
        print(tz_status_at(winter, "America/Los_Angeles").abbr)   # PST
    """
    tz = ZoneInfo(tz_key)
    local = dt.astimezone(tz)
    offset = local.utcoffset() or datetime.timedelta(0)
    dst    = local.dst() or datetime.timedelta(0)
    abbr   = local.strftime("%Z")
    return TzStatus(key=tz_key, utcoffset=offset, abbr=abbr, is_dst=bool(dst))


def utc_offset_hours(tz_key: str, at: "datetime.datetime | None" = None) -> float:
    """
    Return the UTC offset in hours for tz_key at a given moment (default: now).

    Example:
        print(utc_offset_hours("Asia/Kolkata"))       # 5.5
        print(utc_offset_hours("America/New_York"))   # -5.0 or -4.0 (DST)
    """
    ref = (at or utc_now()).astimezone(ZoneInfo(tz_key))
    offset = ref.utcoffset() or datetime.timedelta(0)
    return offset.total_seconds() / 3600


# ─────────────────────────────────────────────────────────────────────────────
# 4. Multi-region time display
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class RegionTime:
    """One row in a multi-region display."""
    zone_key:   str
    local_time: str
    utc_offset: str
    abbr:       str


def world_clock(
    tz_keys: "list[str]",
    at: "datetime.datetime | None" = None,
    fmt: str = "%Y-%m-%d %H:%M:%S",
) -> list[RegionTime]:
    """
    Return current local time for each timezone key.

    Example:
        for row in world_clock(["UTC", "America/New_York", "Asia/Tokyo", "Europe/Paris"]):
            print(f"{row.zone_key:30s}  {row.local_time}  {row.utc_offset}  {row.abbr}")
    """
    ref = at or utc_now()
    rows = []
    for key in tz_keys:
        tz = get_tz(key)
        if tz is None:
            continue
        local = ref.astimezone(tz)
        offset = local.utcoffset() or datetime.timedelta(0)
        h, rem = divmod(int(offset.total_seconds()), 3600)
        m = abs(rem) // 60
        offset_str = f"UTC{h:+03d}:{m:02d}"
        rows.append(RegionTime(
            zone_key=key,
            local_time=local.strftime(fmt),
            utc_offset=offset_str,
            abbr=local.strftime("%Z"),
        ))
    return rows


def schedule_utc(
    naive_local: datetime.datetime,
    tz_key: str,
) -> datetime.datetime:
    """
    Given a naive local datetime in tz_key, return the equivalent UTC moment.
    Useful for scheduling events entered in local time.

    Example:
        # User says "9 AM tomorrow in Berlin"
        import datetime
        local = datetime.datetime(2024, 6, 15, 9, 0)
        utc = schedule_utc(local, "Europe/Berlin")
        print(utc)   # 2024-06-15 07:00:00+00:00
    """
    aware = naive_local.replace(tzinfo=ZoneInfo(tz_key))
    return aware.astimezone(ZoneInfo("UTC"))


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== zoneinfo demo ===")

    # ── search_timezones ──────────────────────────────────────────────────────
    print("\n--- search_timezones ---")
    for term in ["london", "tokyo", "kolkata"]:
        results = search_timezones(term)
        print(f"  {term!r}: {results}")

    # ── now_in / utc_now ──────────────────────────────────────────────────────
    print("\n--- now_in ---")
    for key in ["UTC", "America/New_York", "Europe/Berlin", "Asia/Tokyo"]:
        t = now_in(key)
        print(f"  {key:25s}  {t.isoformat()}")

    # ── convert_tz ────────────────────────────────────────────────────────────
    print("\n--- convert_tz ---")
    utc_dt = datetime.datetime(2024, 7, 4, 18, 0, tzinfo=ZoneInfo("UTC"))
    for target in ["America/Los_Angeles", "Europe/London", "Asia/Kolkata"]:
        local = convert_tz(utc_dt, target)
        print(f"  {utc_dt.isoformat()}{local.isoformat()}  ({target})")

    # ── tz_status_at ──────────────────────────────────────────────────────────
    print("\n--- tz_status_at ---")
    summer = datetime.datetime(2024, 7, 1, 12, tzinfo=ZoneInfo("UTC"))
    winter = datetime.datetime(2024, 1, 1, 12, tzinfo=ZoneInfo("UTC"))
    for dt, label in [(summer, "summer"), (winter, "winter")]:
        s = tz_status_at(dt, "America/New_York")
        print(f"  {label}: {s.abbr}  UTC{s.offset_hours():+.1f}h  DST={s.is_dst}")

    # ── world_clock ───────────────────────────────────────────────────────────
    print("\n--- world_clock ---")
    ref = datetime.datetime(2024, 6, 15, 12, 0, tzinfo=ZoneInfo("UTC"))
    for row in world_clock(
        ["UTC", "America/New_York", "Europe/Paris", "Asia/Kolkata", "Asia/Tokyo"],
        at=ref,
    ):
        print(f"  {row.zone_key:25s}  {row.local_time}  {row.utc_offset}  {row.abbr}")

    # ── schedule_utc ───────────────────────────────────────────────────────────
    print("\n--- schedule_utc ---")
    local_event = datetime.datetime(2024, 9, 20, 9, 30)
    utc_event = schedule_utc(local_event, "Europe/Berlin")
    print(f"  Local (Berlin): {local_event}  →  UTC: {utc_event}")

    # ── utc_offset_hours ──────────────────────────────────────────────────────
    print("\n--- utc_offset_hours ---")
    ref2 = datetime.datetime(2024, 1, 15, 12, tzinfo=ZoneInfo("UTC"))
    for key in ["Asia/Kolkata", "Australia/Adelaide", "Pacific/Chatham"]:
        h = utc_offset_hours(key, at=ref2)
        print(f"  {key:25s}  UTC{h:+.2f}h")

    print("\n=== done ===")

For the pytz (PyPI) alternative — pytz pre-dates zoneinfo and uses pytz.timezone("America/New_York").localize(naive_dt) for safe localization and dt.astimezone(tz) for conversion; it bundles its own timezone data independently of the OS — prefer zoneinfo (stdlib, Python 3.9+) for all new code; use pytz only when supporting Python < 3.9 or when a library dependency requires it. For the dateutil (PyPI) tz module alternative — dateutil.tz.gettz("America/New_York") also returns a tzinfo object using the OS timezone database and adds tzoffset, tzlocal, tzutc convenience classes — use dateutil.tz when you need its parser integration (dateutil.parser.parse) or robust fuzzy timezone string resolution; use zoneinfo when you want a stdlib-only solution with the same IANA database. The Claude Skills 360 bundle includes zoneinfo skill sets covering get_tz()/tz_or_utc()/search_timezones()/list_region_zones() lookup helpers, now_in()/utc_now()/to_utc()/convert_tz()/localize_naive() conversion utilities, TzStatus dataclass + tz_status_at()/utc_offset_hours() DST inspection, and RegionTime/world_clock()/schedule_utc() multi-region display. Start with the free tier to try timezone patterns and zoneinfo pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free