Skip to content

Utils API

This module contains helper functions for parsing dates and formatting HTTP headers.

Date Parsing

The library supports multiple date formats via the DateInput type alias:

  1. ISO 8601 Strings: "2024-01-01", "2024-01-01T12:00:00Z"
  2. Date/Datetime Objects: datetime.date(2024, 1, 1), datetime.datetime(2024, 1, 1, 12, 0, 0)
  3. Integers/Floats: Unix timestamps

All dates are internally converted to UTC timestamps for the Deprecation header (as per RFC 9745) and HTTP-date format for the Sunset header.

Reference

fastapi_deprecation.utils

format_deprecation_date(value)

Format date for 'Deprecation' header (RFC 9745). Format: @ (RFC 9651 Date)

Source code in src/fastapi_deprecation/utils.py
def format_deprecation_date(value: DateInput) -> str:
    """
    Format date for 'Deprecation' header (RFC 9745).
    Format: @<timestamp> (RFC 9651 Date)
    """
    dt = parse_date(value)
    timestamp = int(dt.timestamp())
    return f"@{timestamp}"

format_sunset_date(value)

Format date for 'Sunset' header (RFC 8594). Format: HTTP-date (RFC 7231)

Source code in src/fastapi_deprecation/utils.py
def format_sunset_date(value: DateInput) -> str:
    """
    Format date for 'Sunset' header (RFC 8594).
    Format: HTTP-date (RFC 7231)
    """
    dt = parse_date(value)
    return format_datetime(dt, usegmt=True)

parse_date(value)

Parse input into a timezone-aware UTC datetime object.

Supports: - datetime (converted to UTC) - date (converted to UTC midnight) - str (parsed via dateutil, assumed UTC if allowed, or local if implied) - int/float (Unix timestamp)

Source code in src/fastapi_deprecation/utils.py
def parse_date(value: DateInput) -> datetime:
    """
    Parse input into a timezone-aware UTC datetime object.

    Supports:
    - datetime (converted to UTC)
    - date (converted to UTC midnight)
    - str (parsed via dateutil, assumed UTC if allowed, or local if implied)
    - int/float (Unix timestamp)
    """
    if isinstance(value, datetime):
        if value.tzinfo is None:
            # Assume UTC for naive to avoid "it works on my machine" issues.
            return value.replace(tzinfo=timezone.utc)
        return value.astimezone(timezone.utc)

    if isinstance(value, date):
        return datetime(value.year, value.month, value.day, tzinfo=timezone.utc)

    if isinstance(value, (int, float)):
        return datetime.fromtimestamp(value, tz=timezone.utc)

    if isinstance(value, str):
        try:
            dt = dateutil.parser.parse(value)
            if dt.tzinfo is None:
                dt = dt.replace(tzinfo=timezone.utc)
            return dt.astimezone(timezone.utc)
        except (ValueError, OverflowError):
            raise ValueError(f"Invalid date string: {value}")

    raise TypeError(f"Unsupported date type: {type(value)}")