Pydantic: [Question] how to do constrained string that accepts datetime string only?

Created on 9 May 2020  路  5Comments  路  Source: samuelcolvin/pydantic

Question

version 1.5.1

How do I do a constrained string that only accepts datetime string format that should look like this?

"2020-05-06 09:40:18"

I know i can do a regex but is that the best way?

question

Most helpful comment

I'd recommend using the Pendulum library, which will parse things by default to UTC timezone: https://pendulum.eustace.io/docs/#parsing and add numerous fluent helpers for easier working with datetimes and timezones.

All 5 comments

@simkimsia
You can use @validator to check input data.

https://pydantic-docs.helpmanual.io/usage/validators/

import datetime
from typing import Any

from pydantic import BaseModel, validator


class Model(BaseModel):
    time: datetime.datetime

    @validator("time")
    def validate_time(cls, value: Any) -> Any:
        if value == "xxx":  # <- Here is condition checking your format.
            return value
        raise ValueError("Invalid format")

Also, If the field type is str then, you can use constr(regex="").
https://pydantic-docs.helpmanual.io/usage/types/#constrained-types

Thanks @koxudaxi

I will be running parse_obj on a json dictionary. The parsed output should be a datetime object. Unfortunately, the json being passed to my system uses a string of the following format

Y-m-d H:M:S

e.g. "2020-05-10 23:48:38"

So that motivates this question. I want to ensure that the data coming in at least has this format but not less.

Acceptable formats include

"%Y-%m-%dT%H:%M:%S.%f%z",
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%dT%H:%M:%S",
"%Y-%m-%dT%H:%M:%S.%f%zZ",

# but not 
"%Y-%m-%d",

just as an example to illustrate

@simkimsia

You can use re.match in a validation method.
Also, You should set @validator('time', pre=True) to check input data as a string before parse data to datetime.

https://pydantic-docs.helpmanual.io/usage/validators/#pre-and-per-item-validators

import datetime
import re
from typing import Any

from pydantic import BaseModel, validator

VALID_FORMAT_PATTERN = r'xxxx'  # you write correct regex pattern in here.
class Model(BaseModel):
    time: datetime.datetime

    @validator("time", pre=True)
    def validate_time(cls, value: Any) -> Any:
        if  isinstance(value, str) and match(VALID_FORMAT_PATTERN, value): 
            return value
        raise ValueError("Invalid format")

Sorry I got pulled away to handle some task. Will test ur answer tomorrow.

In the meantime, I see that I got some RunTimeWarning abt receiving naive datetime object from my pydantic entities.

How do I parse the datetime out as default to UTC timezone?

I'd recommend using the Pendulum library, which will parse things by default to UTC timezone: https://pendulum.eustace.io/docs/#parsing and add numerous fluent helpers for easier working with datetimes and timezones.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaheba picture jaheba  路  25Comments

Gaunt picture Gaunt  路  19Comments

dand-oss picture dand-oss  路  19Comments

rrbarbosa picture rrbarbosa  路  35Comments

jasonkuhrt picture jasonkuhrt  路  19Comments