Skip to content

flight_summary.get_light and get_full Send Datetime Params in Wrong Format #41

@jayfiro

Description

@jayfiro

flight_summary.get_light / get_full send datetime params in wrong format, API returns 400

Summary

FlightSummaryResource.get_light() and get_full() accept flight_datetime_from and flight_datetime_to as Python datetime objects, but serialize them with str(), which produces the format 2026-05-17 00:00:00+00:00 (space separator, with tz offset). The Flightradar24 API requires ISO 8601 in the format YYYY-MM-DDTHH:MM:SS (T separator, no offset), so every call with these parameters fails with a 400.

Environment

  • fr24sdk version: 0.3.0 (latest as of report)
  • Python: 3.10
  • httpx: bundled with SDK

Minimal reproduction

from datetime import datetime, timezone
from fr24sdk.client import Client

with Client(api_token="<token>") as client:
    client.flight_summary.get_full(
        flights=["AA123"],
        flight_datetime_from=datetime(2026, 5, 17, tzinfo=timezone.utc),
        flight_datetime_to=datetime(2026, 5, 20, 23, 59, 59, tzinfo=timezone.utc),
    )

Actual outgoing request

GET https://fr24api.flightradar24.com/api/flight-summary/full
    ?flight_datetime_from=2026-05-17%2000%3A00%3A00%2B00%3A00
    &flight_datetime_to=2026-05-20%2023%3A59%3A59%2B00%3A00
    &flights=AA123

Actual response

fr24sdk.exceptions.BadRequestError: 400 Bad Request:
The 'flight_datetime_from' field must be a valid datetime in the format 'YYYY-MM-DDTHH:MM:SS'.,
The 'flight_datetime_to' field must be a valid datetime in the format 'YYYY-MM-DDTHH:MM:SS'.

Expected outgoing request

GET https://fr24api.flightradar24.com/api/flight-summary/full
    ?flight_datetime_from=2026-05-17T00%3A00%3A00
    &flight_datetime_to=2026-05-20T23%3A59%3A59
    &flights=AA123

The reproduction fails the same way when datetime objects are passed naive (no tzinfo) — str(datetime(2026, 5, 17)) produces '2026-05-17 00:00:00', which still uses a space rather than T.

Root cause

src/fr24sdk/resources/flight_summary.py, in _FlightSummaryParams._to_query_dict:

@model_serializer(mode="plain")
def _to_query_dict(self) -> dict[str, Any]:
    query: dict[str, Any] = {}
    for key, value in self.__dict__.items():
        if value is None:
            continue
        if isinstance(value, list):
            query[key] = ",".join(map(str, value))
        else:
            query[key] = str(value)   # ← bug: str(datetime) is not ISO 8601
    return query

str(datetime(...)) uses datetime.__str__, which is equivalent to isoformat(sep=' '). The API requires isoformat(sep='T') (and no timezone suffix).

Suggested fix

Special-case datetime (and date) in the serializer so they're formatted to the API's expected shape:

from datetime import date, datetime

@model_serializer(mode="plain")
def _to_query_dict(self) -> dict[str, Any]:
    query: dict[str, Any] = {}
    for key, value in self.__dict__.items():
        if value is None:
            continue
        if isinstance(value, list):
            query[key] = ",".join(map(str, value))
        elif isinstance(value, datetime):
            # API spec requires YYYY-MM-DDTHH:MM:SS with no timezone
            naive = value.astimezone(timezone.utc).replace(tzinfo=None) if value.tzinfo else value
            query[key] = naive.strftime("%Y-%m-%dT%H:%M:%S")
        elif isinstance(value, date):
            query[key] = value.isoformat()
        else:
            query[key] = str(value)
    return query

(If the API accepts/expects UTC offsets in the future, this can be adjusted, but the current docs and 400 message specify the un-offset format.)

Impact

  • flight_summary.get_light(), get_full(), get_count(), and the deprecated count() are all affected.
  • Any other resource whose _to_query_dict runs a datetime through str() is likely affected the same way. A grep for model_serializer + str(value) in src/fr24sdk/resources/ would surface any others.

Workaround we're using

Bypassing the typed resource and calling client.transport.request() directly with pre-formatted strings:

client.transport.request(
    "GET",
    "/api/flight-summary/full",
    params={
        "flights": flight_code,
        "flight_datetime_from": window_start.strftime("%Y-%m-%dT%H:%M:%S"),
        "flight_datetime_to": window_end.strftime("%Y-%m-%dT%H:%M:%S"),
    },
)

This works but gives up the typed parameter validation that's the main point of the SDK wrapper.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions