timezone in api
I've been working on adding timezone support for the fixture details endpoint /football/fixtures?date=2025-03-29
The easiest and correct way to do this is by adding timezone
as a query parameter to the endpoint
GET /football/fixtures?date=2025-03-29&timezone=America/Los_Angeles
Things to consider
- you need to validate the timezone using
pytz
andzoneinfo
library - convert server timestamps to local timezone before returning
example fast api python code
from fastapi import FastAPI, Query, HTTPException
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
import pytz # if using Python < 3.9
app = FastAPI()
@app.get("/football/fixtures")
def get_fixtures(date: str = Query(...), timezone: str = Query("UTC")):
try:
# Parse input date
input_date = datetime.strptime(date, "%Y-%m-%d")
# Validate timezone
try:
tz = ZoneInfo(timezone)
except Exception:
raise HTTPException(status_code=400, detail="Invalid timezone")
# Convert input date to UTC range
start_dt = input_date.replace(tzinfo=tz).astimezone(ZoneInfo("UTC"))
end_dt = (input_date + timedelta(days=1)).replace(tzinfo=tz).astimezone(ZoneInfo("UTC"))
# Query fixtures in that UTC range
fixtures = query_fixtures_between(start_dt, end_dt)
# Convert match times to client's timezone
for f in fixtures:
f["match_time_local"] = f["match_time_utc"].astimezone(tz).isoformat()
return fixtures
except ValueError:
raise HTTPException(status_code=400, detail="Invalid date format. Use YYYY-MM-DD.")
example of parsing the timezone to select games between 00:00 to 11:59 of the localized date
@app.get("/football/fixtures")
def get_football_fixtures(
date: Optional[str] = Query(None, description="Date in YYYY-MM-DD format"),
has_odds: bool = Query(True, description="Filter fixtures that have odds data"),
timezone: Optional[str] = Query(None, description="Timezone in IANA format (e.g., America/Los_Angeles)"),
db: Session = Depends(get_db)
):
from datetime import timedelta
from zoneinfo import ZoneInfo
# Build the base query
query = db.query(FootballFixture)
# Apply date filter if provided
if date:
try:
# Parse the date string to datetime object
parsed_date = datetime.strptime(date, "%Y-%m-%d")
# Apply timezone conversion if timezone is provided
if timezone:
try:
tz = ZoneInfo(timezone)
# Set the start and end of the day in the specified timezone
localized_start = datetime(parsed_date.year, parsed_date.month, parsed_date.day, 0, 0, 0, 0, tzinfo=tz)
localized_end = datetime(parsed_date.year, parsed_date.month, parsed_date.day, 23, 59, 59, 999999, tzinfo=tz)
# Convert to UTC for database comparison
utc_start = localized_start.astimezone(ZoneInfo("UTC"))
utc_end = localized_end.astimezone(ZoneInfo("UTC"))
# Filter fixtures for the specified date in the timezone (from 12:00am to 11:59:59.999999pm)
query = query.filter(
FootballFixture.date >= utc_start,
FootballFixture.date <= utc_end
)
except Exception:
return {
"get": "fixtures",
"parameters": {"date": date, "timezone": timezone},
"errors": ["Invalid timezone format. Please use IANA timezone format (e.g., America/Los_Angeles)."],
"results": 0,
"response": []
}
else:
# No timezone specified, use UTC
query = query.filter(
FootballFixture.date >= datetime.combine(parsed_date.date(), datetime.min.time()),
FootballFixture.date < datetime.combine(parsed_date.date() + timedelta(days=1), datetime.min.time())
)
except ValueError:
return {
"get": "fixtures",
"parameters": {"date": date, "timezone": timezone} if timezone else {"date": date},
"errors": ["Invalid date format. Please use YYYY-MM-DD format."],
"results": 0,
"response": []
}
encoding the url because the urls cannot contain raw slashes
Timezone: America/Los_Angeles
should be encoded to
America%2FLos_Angeles
the example url should look like this
http://localhost:8000/football/fixtures?date=2025-03-29&timezone=America%2FLos_Angeles
when working from the client, for example, ios, use encode a url in swift