Skip to content

New API for date-like types unit/format configuration #12068

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

ollz272
Copy link
Contributor

@ollz272 ollz272 commented Jul 17, 2025

Change Summary

Following work on the pydantic-core branch, this PR implements the config hooks to allow ser_json_temporal to be passed in.

Related issue number

Fixes #10454
Fixes #7940

Performance improvements

The main reason we wanted this was to improve performance when we want to serialize a datetime as a millisecond timestamp. Below is a small script using this branch:

from typing import Annotated

import pendulum
import datetime as dt
from pydantic import BaseModel, PlainSerializer
import tqdm

import time

RANGE = 10

dts = [dt for dt in pendulum.interval(
    pendulum.datetime(2023, 1, 1),
    pendulum.datetime(2024, 1, 1)
).range("seconds", 30)]


T_SerializedDatetime = Annotated[
    dt.datetime,
    PlainSerializer(
        lambda x: x.timestamp() * 1000,
        return_type=float,
        when_used="json",
    ),
]

class MyModelOld(BaseModel):
    """A model with a datetime field."""

    dts: list[T_SerializedDatetime]


class MyModelNew(BaseModel):
    """A model with a datetime field."""

    dts: list[dt.datetime]

    model_config = {
        "ser_json_temporal": "milliseconds"
    }

instance_old = MyModelOld(dts=dts)
instance_new = MyModelNew(dts=dts)

t = time.time()
for _ in tqdm.tqdm(range(RANGE)):
    instance_old.model_dump_json()
print(time.time() - t)

t = time.time()
for _ in tqdm.tqdm(range(RANGE)):
    instance_new.model_dump_json()
print(time.time() - t)

I've run this over a few different number of dts to try gauge performance. A note is that im not 100% sure how this is being built for me when im installing, i doubt its using PGO and not sure if its the dev or prod profile, so i'd guess performance will improve from these results.

For the second conversion:

num_datetimes num_iterations old_avg_speed(s) new_avg_speed (s) improvment (%)
366 240000 0.0002707 0.0002708 24.5%
8761 10000 0.006218 0.005001 19.5%
525601 166 0.3795 0.2928 22.8%
1051201 166 0.7668 0.5604 26.9%

and for the millisecond conversion:

num_datetimes num_iterations old_avg_speed(s) new_avg_speed (s) improvment (%)
366 10000 0.0002723 0.0002100 22.8%
8761 10000 0.006659 0.004849 27.2%
525601 166 0.4029 0.2900 28.0%
1051201 166 0.7933 0.5755 27.4%

So for us, this is a great improvement, esspecially for when we need to return large timeseries.

NOTE: currently based against a branch of pydantic-core, because theres no pydantic core release yet.

Checklist

  • The pull request title is a good summary of the changes - it will be used in the changelog
  • [] Unit tests for the changes exist
  • Tests pass on CI
  • Documentation reflects the changes where applicable
  • My PR is ready to review, please add a comment including the phrase "please review" to assign reviewers

Selected Reviewer: @Viicos

@ollz272 ollz272 changed the title implement ser_json_temporal configuration opetion implement ser_json_temporal configuration option Jul 17, 2025
@github-actions github-actions bot added the relnotes-fix Used for bugfixes. label Jul 17, 2025
Copy link

codspeed-hq bot commented Jul 17, 2025

CodSpeed Performance Report

Merging #12068 will not alter performance

Comparing ollz272:implement_ser_json (ecbc4ec) with main (1c79f0e)

Summary

✅ 46 untouched benchmarks

@ollz272 ollz272 force-pushed the implement_ser_json branch from 460430b to b268079 Compare August 8, 2025 09:12
@ollz272 ollz272 changed the title implement ser_json_temporal configuration option New API for date-like types unit/format configuration Aug 8, 2025
@ollz272
Copy link
Contributor Author

ollz272 commented Aug 8, 2025

Please review

Copy link
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  pydantic
  config.py
  version.py
  pydantic/_internal
  _config.py
Project Total  

This report was generated by python-coverage-comment-action

@ollz272
Copy link
Contributor Author

ollz272 commented Aug 11, 2025

@Viicos I think this is all sorted now and ready to merge in for 2.12 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants