FastAPI validate timezones

Photo by Luis Cortes on Unsplash

If you aren’t familiar with Python, FastAPI or Timezones, this might not be the post for you, sorry.

For the rest of you geeks (like me), here is an example how to validate supported timezones in an input (Query, Path etc.). Scratch that, this is about how to validate dynamic lists of values in FastAPI by using timezones as an example.

As you know, in FastAPI you can validate predefined values by using String Enums (A class sub-classed from str and Enum), so how do you validate dynamic lists of values?

According to the docs, this is how you create a dynamic Enum:

>>> from datetime import timedelta
>>> class Period(timedelta, Enum):
...     "different lengths of time"
...     _ignore_ = 'Period i'
...     Period = vars()
...     for i in range(367):
...         Period['day_%d' % i] = i

The _ignore_ part is to remove the variable generated by the property Period and the for loop, of course.

Back to Timezones, according to the docs you can get the list of timezones supported by the locally installed IANA timezone DB:

import zoneinfo
zoneinfo.available_timezones()

And to our mini validation example:

import zoneinfo
from datetime import datetime
from enum import Enum

from fastapi import FastAPI, Query

app = FastAPI()


class Timezone(str, Enum):
    _ignore_ = 'Timezone z'
    Timezone = vars()
    for z in zoneinfo.available_timezones():
        Timezone[z] = z


@app.get('/')
def get_time(zone: Timezone = Query(Timezone.UTC)):
    return {'now': datetime.now(tz=zoneinfo.ZoneInfo(zone))}

This way you can accept a timezone string, but not inserting it into any function without validating it is a string you can trust, and in the same time you don’t have to maintain that list on your own.

Remember #1: that the timezone list is recalculated every time the function is called (app start in this case), so if you run this directly on a machine, remember to restart the app after updating the timezone DB.

Remember #2: that most of the Enum items aren’t accessible in the class instance notation, Timezone.America/New_York, but you can access it using the dict notation Timezone['America/New_York'], The common names of course are accessible, like Timezone.UTC and Timezone.EST.