If you want the model to still hold an actual date object in that field, you should definitely leave the annotation as date_of_birth: date rather than simply switching to str.

If you want to allow strings with a particular format to be passed as a special case, you should define a pre=True validator that will check for strings and attempt to parse those accordingly. This is similar to @suraj's answer, but has the advantage of type safety.

For even more clarity, you could set your desired date format as a class variable on the module.

For the API, you could leverage the fact that the JSON Schema specs allow the format keyword for string types with custom format specifications. You could extend the automatically generated schema for the model to display for example that same date format for every date type field in the model instead of just showing the standard format called "date". Note that there is no special type for dates in JSON, so the Swagger UI would always have to show that field as string regardless.

Lastly, to make it crystal clear for users of the API what that format represents, you could add an example data object to the schema at the end.

Here is the full code I suggest:

from __future__ import annotations
from datetime import date, datetime
from typing import Any, ClassVar

from pydantic import BaseModel, validator


class Profile(BaseModel):
    date_format: ClassVar[str] = "%d-%b-%Y"
    example_data: ClassVar[dict[str, Any]] = {
        "name": "John Doe",
        "date_of_birth": "15-Jul-1996",
        "gender": "m",
    }

    name: str
    date_of_birth: date
    gender: str

    @validator("date_of_birth", pre=True)
    def string_to_date(cls, v: object) -> object:
        if isinstance(v, str):
            return datetime.strptime(v, cls.date_format).date()
        return v

    class Config:
        @staticmethod
        def schema_extra(schema: dict[str, Any], model: type[Profile]) -> None:
            for name, field in model.__fields__.items():
                if field.type_ is date:
                    schema["properties"][name]["format"] = model.date_format
            schema["examples"] = [model.example_data]

Demo:

profile_example = Profile.parse_obj(Profile.example_data)
print(profile_example.json(indent=4))
print(Profile.schema_json(indent=4))

Output:

{
    "name": "John Doe",
    "date_of_birth": "1996-07-15",
    "gender": "m"
}
{
    "title": "Profile",
    "type": "object",
    "properties": {
        "name": {
            "title": "Name",
            "type": "string"
        },
        "date_of_birth": {
            "title": "Date Of Birth",
            "type": "string",
            "format": "%d-%b-%Y"
        },
        "gender": {
            "title": "Gender",
            "type": "string"
        }
    },
    "required": [
        "name",
        "date_of_birth",
        "gender"
    ],
    "examples": [
        {
            "name": "John Doe",
            "date_of_birth": "15-Jul-1996",
            "gender": "m"
        }
    ]
}

Even if you don't want to go the extra mile with the schema customization, I would still argue for using the proper field type and pre-validating strings instead.

Here is the minimal version:

from datetime import date, datetime

from pydantic import BaseModel, validator


class Profile(BaseModel):
    name: str
    date_of_birth: date
    gender: str

    @validator("date_of_birth", pre=True)
    def string_to_date(cls, v: object) -> object:
        if isinstance(v, str):
            return datetime.strptime(v, "%d-%b-%Y").date()
        return v

The disadvantage is that the format default shown in the JSON Schema is date, which has a different meaning and is equivalent to %d-%m-%Y, which obviously does not fit your actual requirements. But parsing would still work of course with that validator.

Answer from Daniel Fainberg on Stack Overflow
🌐
FastAPI
fastapi.tiangolo.com › tutorial › extra-data-types
Extra Data Types - FastAPI
September 15, 2008 - Standard Python Decimal. In requests and responses, handled the same as a float. You can check all the valid Pydantic data types here: Pydantic data types. Here's an example path operation with parameters using some of the above types. ... from datetime import datetime, time, timedelta from typing import Annotated from uuid import UUID from fastapi import Body, FastAPI app = FastAPI() @app.put("/items/{item_id}") async def read_items( item_id: UUID, start_datetime: Annotated[datetime, Body()], end_datetime: Annotated[datetime, Body()], process_after: Annotated[timedelta, Body()], repeat_at: An
🌐
Orchestra
getorchestra.io › guides › fastapi-and-datetime-types-a-comprehensive-guide
FastAPI and Datetime Types: A Comprehensive Guide | Orchestra
March 20, 2024 - Handling date and time types ... web applications. By leveraging Python's datetime module and FastAPI's seamless integration with Pydantic, you can efficiently manage datetime data in your APIs....
Discussions

python - FastAPI: datetime with timezone in request doesn't work - Stack Overflow
from fastapi import FastAPI from datetime import datetime from ..models import Contact from ..database import Database app = FastAPI() # Dependency def get_db(): db = Database() try: More on stackoverflow.com
🌐 stackoverflow.com
FastAPI Query Parameters with datetime.date not updating default value?
First Check I added a very descriptive title here. I used the GitHub search to find a similar question and didn't find it. I searched the FastAPI documentation, with the integrated search. I al... More on github.com
🌐 github.com
3
1
Using default for datetime query parameter without timezone leads to OpenAPI SpecValidationException
First check I added a very descriptive title to this issue. I used the GitHub search to find a similar issue and didn't find it. I searched the FastAPI documentation, with the integrated search. I ... More on github.com
🌐 github.com
9
December 15, 2020
How to maintain the datetime format same as input
First check I added a very descriptive title to this issue. I used the GitHub search to find a similar issue and didn't find it. I searched the FastAPI documentation, with the integrated search. I ... More on github.com
🌐 github.com
7
May 6, 2021
Top answer
1 of 2
7

If you want the model to still hold an actual date object in that field, you should definitely leave the annotation as date_of_birth: date rather than simply switching to str.

If you want to allow strings with a particular format to be passed as a special case, you should define a pre=True validator that will check for strings and attempt to parse those accordingly. This is similar to @suraj's answer, but has the advantage of type safety.

For even more clarity, you could set your desired date format as a class variable on the module.

For the API, you could leverage the fact that the JSON Schema specs allow the format keyword for string types with custom format specifications. You could extend the automatically generated schema for the model to display for example that same date format for every date type field in the model instead of just showing the standard format called "date". Note that there is no special type for dates in JSON, so the Swagger UI would always have to show that field as string regardless.

Lastly, to make it crystal clear for users of the API what that format represents, you could add an example data object to the schema at the end.

Here is the full code I suggest:

from __future__ import annotations
from datetime import date, datetime
from typing import Any, ClassVar

from pydantic import BaseModel, validator


class Profile(BaseModel):
    date_format: ClassVar[str] = "%d-%b-%Y"
    example_data: ClassVar[dict[str, Any]] = {
        "name": "John Doe",
        "date_of_birth": "15-Jul-1996",
        "gender": "m",
    }

    name: str
    date_of_birth: date
    gender: str

    @validator("date_of_birth", pre=True)
    def string_to_date(cls, v: object) -> object:
        if isinstance(v, str):
            return datetime.strptime(v, cls.date_format).date()
        return v

    class Config:
        @staticmethod
        def schema_extra(schema: dict[str, Any], model: type[Profile]) -> None:
            for name, field in model.__fields__.items():
                if field.type_ is date:
                    schema["properties"][name]["format"] = model.date_format
            schema["examples"] = [model.example_data]

Demo:

profile_example = Profile.parse_obj(Profile.example_data)
print(profile_example.json(indent=4))
print(Profile.schema_json(indent=4))

Output:

{
    "name": "John Doe",
    "date_of_birth": "1996-07-15",
    "gender": "m"
}
{
    "title": "Profile",
    "type": "object",
    "properties": {
        "name": {
            "title": "Name",
            "type": "string"
        },
        "date_of_birth": {
            "title": "Date Of Birth",
            "type": "string",
            "format": "%d-%b-%Y"
        },
        "gender": {
            "title": "Gender",
            "type": "string"
        }
    },
    "required": [
        "name",
        "date_of_birth",
        "gender"
    ],
    "examples": [
        {
            "name": "John Doe",
            "date_of_birth": "15-Jul-1996",
            "gender": "m"
        }
    ]
}

Even if you don't want to go the extra mile with the schema customization, I would still argue for using the proper field type and pre-validating strings instead.

Here is the minimal version:

from datetime import date, datetime

from pydantic import BaseModel, validator


class Profile(BaseModel):
    name: str
    date_of_birth: date
    gender: str

    @validator("date_of_birth", pre=True)
    def string_to_date(cls, v: object) -> object:
        if isinstance(v, str):
            return datetime.strptime(v, "%d-%b-%Y").date()
        return v

The disadvantage is that the format default shown in the JSON Schema is date, which has a different meaning and is equivalent to %d-%m-%Y, which obviously does not fit your actual requirements. But parsing would still work of course with that validator.

2 of 2
0

Try this. You can use @validator

from pydantic import BaseModel, validator
from datetime import datetime

class Profile(BaseModel):
    name: str
    DOB: str  # change this to str
    gender: str

    @validator('DOB')
    def parse_dob(cls, v):
        return datetime.strptime(v, '%d-%b-%Y').date()  # convert string to date

🌐
Top Tech Tips
toptechtips.github.io › 2023-05-28-how-to-return-datetime-fastapi
How to return datetime, dicts, lists, xml, pydantic models and other data types response in fastAPI (With Examples)
May 28, 2023 - Convert return data into JSON-compatible data (e.g. a python dict) FastAPI uses JSONReponse(content=JSON-compatible data) behind the scenes ... You can however skip all this and create your own custom response using JSONResponse, Response (or any other subclass of Response) - But more on this after these examples. @app.get("/item") async def get_item(): return {"item": "toy"} ... datetime.datetime: A Python datetime.datetime.
Find elsewhere
🌐
Readthedocs
fastapi-contrib.readthedocs.io › en › latest › _modules › fastapi_contrib › common › utils.html
fastapi_contrib.common.utils — FastAPI Contrib 0.2.11 documentation
import importlib import sys import pytz from datetime import datetime from functools import wraps from time import time from typing import Any from fastapi import FastAPI from fastapi_contrib.conf import settings · [docs]def resolve_dotted_path(path: str) -> Any: """ Retrieves attribute (var, function, class, etc.) from module by dotted path .. code-block:: python from datetime.datetime import utcnow as default_utcnow utcnow = resolve_dotted_path('datetime.datetime.utcnow') assert utcnow == default_utcnow :param path: dotted path to the attribute in module :return: desired attribute or None """ splitted = path.split(".") if len(splitted) <= 1: return importlib.import_module(path) module, attr = ".".join(splitted[:-1]), splitted[-1] module = importlib.import_module(module) return getattr(module, attr)
🌐
GitHub
github.com › fastapi › fastapi › issues › 2519
Using default for datetime query parameter without timezone leads to OpenAPI SpecValidationException · Issue #2519 · fastapi/fastapi
December 15, 2020 - I already checked if it is not related to FastAPI but to ReDoc. ... Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. Implement a Pull Request for a confirmed bug. Here's a self-contained, minimal, reproducible, example with my use case: from datetime import datetime from fastapi import FastAPI import uvicorn app = FastAPI() start = datetime.today() @app.get("/") async def root(start_date: datetime = start): print(start_date) return {"start_date": start_date} if __name__ == "__main__": uvicorn.run(app, host="127.0.0.1", port=8000)
Author   johnthagen
🌐
Medium
medium.com › @rameshkannanyt0078 › how-to-handle-timezones-properly-in-fastapi-and-database-68b1c019c1bc
📌 How to Handle Timezones Properly in FastAPI and Database | by Ramesh Kannan s | Medium
April 28, 2025 - from pydantic import BaseModel from datetime import datetime class TokenData(BaseModel): access_token: str refresh_token: str issued_at: datetime # will parse and validate ISO8601 UTC datetimes expires_at: datetime · When FastAPI parses or serializes datetime fields:
🌐
GitHub
github.com › fastapi › fastapi › issues › 3183
How to maintain the datetime format same as input · Issue #3183 · fastapi/fastapi
May 6, 2021 - First check I added a very descriptive title to this issue. I used the GitHub search to find a similar issue and didn't find it. I searched the FastAPI documentation, with the integrated search. I already searched in Google "How to X in ...
Author   yantrikskaran
🌐
Stack Overflow
stackoverflow.com › questions › 74728163 › how-to-force-fastapi-to-return-formatted-datetime
python - How to force FastApi to return formatted DateTime - Stack Overflow
According to the documentation, this is how the datetime type is returned: A Python datetime.datetime. In requests and responses will be represented as a str in ISO 8601 format, like: 2008-09-15T...
🌐
Fastapiinteractive
fastapiinteractive.com › fastapi-basics › 10-extra-data-types › theory
Extra Data Types - Theory | FastAPI Basics | FastAPI Tutorial
The official FastAPI documentation now recommends using Annotated for better type hints and IDE support: from typing import Annotated # Modern approach (recommended) start_datetime: Annotated[datetime, Body()] # Older approach (still works) start_datetime: datetime = Body() ... # You can perform normal Python operations start_process = start_datetime + process_after # datetime + timedelta duration = end_datetime - start_process # datetime - datetime is_same_day = start_datetime.date() == end_datetime.date()
🌐
GitHub
github.com › fastapi › fastapi › issues › 2677
Datetime with timezone in request doesn't work · Issue #2677 · fastapi/fastapi
January 19, 2021 - from fastapi import FastAPI from datetime import datetime from ..models import Contact from ..database import Database app = FastAPI() # Dependency def get_db(): db = Database() try: yield db finally: db.disconnect() @app.get("/contacts/", response_model=List[Contact]) async def get_contacts(address: int, start_time: datetime, end_time: datetime, duration: int, distance: int, db: Database = Depends(get_db)): contacts = detect_contacts(db, address, start_time, end_time, duration, distance) return contacts
Author   Pei116
🌐
Stack Overflow
stackoverflow.com › questions › 76551204 › how-to-serialize-post-request-with-datetime-in-fastapi
python 3.x - How to serialize post request with datetime in FastAPI - Stack Overflow
class TaskBase(BaseModel): title: str | None = None description: str | None = None deadline: datetime | None = None class TaskCreate(TaskBase): title: str description: str # performers: list[UserBase] | None = None class Config: orm_mode = True
🌐
FastAPI Tutorial
fastapitutorial.com › blog › introduction-pydantic-for-fastapi
5. Introduction to Pydantic for FastAPI
from pydantic import BaseModel ... 'Python', 'Java', 'Go' We can get the value of the language by querying a blog object as blog_object.language.value 3. Getting dynamic values at runtime The simplest example for this would be to add a property named created_at in the blog. This property should get created dynamically whenever a blog object is created. You might be tempted to think that this is easy, all we need to use is to initialize the property with datetime.no...
🌐
Stack Overflow
stackoverflow.com › questions › 76384677 › python-fastapi-get-date-as-param
mongodb - Python - FastAPI - get date as param - Stack Overflow
from fastapi import FastAPI,HTTPException from pydantic import ( BaseModel, Field, ) # Pydantic = Data validation and settings management using Python type annotations from bson import ObjectId from typing import List import motor.motor_asyncio # Motor = Asynchronous Python driver for MongoDB import datetime app = FastAPI() client = motor.motor_asyncio.AsyncIOMotorClient("mongodb://localhost:27017/") db = client.signal_API class PyObjectId(ObjectId): @classmethod def __get_validators__(cls): yield cls.validate @classmethod def validate(cls, v): if not ObjectId.is_valid(v): raise ValueError("In