How to parse unix timestamp into datetime without timezone in Fast API

Viewed 4112

Assume I have a pydantic model

class EventEditRequest(BaseModel):
    uid: UUID
    name: str
    start_dt: datetime
    end_dt: datetime

I send request with body b'{"uid":"a38a7543-20ca-4a50-ab4e-e6a3ae379d3c","name":"test event2222","start_dt":1600414328,"end_dt":1600450327}'

So both start_dt and end_dt are unix timestamps. But in endpoint they become datetimes with timezones.

@app.put('...')
def edit_event(event_data: EventEditRequest):
    event_data.start_dt.tzinfo is not None  # True

I don't want to manually edit start_dt and end_dt in the endpoint function to get rid of timezones. How can I set up my pydantic model so it will make datetime without timezones?

3 Answers

You can use own @validator to parse datetime manually:

from datetime import datetime

from pydantic import BaseModel, validator


class Model(BaseModel):
    dt: datetime = None


class ModelNaiveDt(BaseModel):
    dt: datetime = None

    @validator("dt", pre=True)
    def dt_validate(cls, dt):
        return datetime.fromtimestamp(dt)


print(Model(dt=1600414328))
print(ModelNaiveDt(dt=1600414328))

Output:

dt=datetime.datetime(2020, 9, 18, 7, 32, 8, tzinfo=datetime.timezone.utc)
dt=datetime.datetime(2020, 9, 18, 10, 32, 8)

Like sashaaero mentions in their answer, you can achieve this with a custom type. But instead of creating your own validation, you could just use the existing validator from Pydantic and then just remove the timezone info.

from pydantic.datetime_parse import parse_datetime


class OffsetNaiveDatetime(datetime):

    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        v = parse_datetime(v)
        v = v.replace(tzinfo=None)
        return v

But be careful to only use it where timezone information is not needed at all or doesn't apply.

One more way to achieve it is to create custom type

class UnixDatetime(datetime):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if isinstance(v, datetime):
            print('Some request sends datetime not in UNIX format', file=sys.stderr)
            return v.replace(tzinfo=None)
        elif isinstance(v, int):
            return datetime.fromtimestamp(v)
        assert False, 'Datetime came of %s type' % type(v)
Related