Serializing Temporal and Binary Types
To serialize temporal (datetime, date, time, timedelta) and binary (bytes) types, use the SchemaSerializer with specific CoreConfig options to control the output format in JSON mode.
Serializing Temporal Types
By default, temporal types are serialized to ISO8601 strings. You can change this behavior globally using the ser_json_temporal configuration option.
from datetime import datetime, timedelta
from pydantic_core import SchemaSerializer, core_schema
# Default ISO8601 serialization
v = SchemaSerializer(core_schema.datetime_schema())
assert v.to_python(datetime(2022, 12, 2, 12, 13, 14), mode='json') == '2022-12-02T12:13:14'
assert v.to_json(datetime(2022, 12, 2, 12, 13, 14)) == b'"2022-12-02T12:13:14"'
# Numeric serialization (seconds or milliseconds)
config = {'ser_json_temporal': 'seconds'}
v_num = SchemaSerializer(core_schema.datetime_schema(), config=config)
assert v_num.to_python(datetime(2022, 12, 2, 12, 13, 14), mode='json') == 1669983194
Customizing Timedelta Serialization
While ser_json_temporal affects all temporal types, you can use ser_json_timedelta to specifically target timedelta objects. Note that ser_json_temporal takes precedence if both are provided.
from datetime import timedelta
from pydantic_core import SchemaSerializer, core_schema
# Default Timedelta (ISO8601 duration)
v = SchemaSerializer(core_schema.timedelta_schema())
assert v.to_python(timedelta(days=2, hours=3), mode='json') == 'P2DT3H'
# Float seconds serialization
config = {'ser_json_timedelta': 'float'}
v_float = SchemaSerializer(core_schema.timedelta_schema(), config=config)
assert v_float.to_python(timedelta(seconds=4, microseconds=500_000), mode='json') == 4.5
Serializing Binary Types
Binary data (bytes) defaults to UTF-8 serialization. If your data contains non-UTF-8 bytes, you must configure an alternative encoding like base64 or hex to avoid errors.
from pydantic_core import SchemaSerializer, core_schema
# Base64 encoding
config_b64 = {'ser_json_bytes': 'base64'}
s_b64 = SchemaSerializer(core_schema.bytes_schema(), config=config_b64)
assert s_b64.to_json(b'foobar') == b'"Zm9vYmFy"'
assert s_b64.to_python(b'foobar', mode='json') == 'Zm9vYmFy'
# Hex encoding
config_hex = {'ser_json_bytes': 'hex'}
s_hex = SchemaSerializer(core_schema.bytes_schema(), config=config_hex)
assert s_hex.to_json(b'foo') == b'"666f6f"'
Temporal Types as Dictionary Keys
When temporal types are used as keys in a dictionary, they are always converted to strings in JSON mode, even if ser_json_temporal is set to a numeric type.
from datetime import date
from pydantic_core import SchemaSerializer, core_schema
schema = core_schema.dict_schema(core_schema.date_schema(), core_schema.int_schema())
v = SchemaSerializer(schema, config={'ser_json_temporal': 'seconds'})
# Even with 'seconds' config, the key is a string ISO8601 date
res = v.to_python({date(2022, 12, 2): 1}, mode='json')
assert res == {'2022-12-02': 1}
Common Gotchas
- UTF-8 Errors: By default (
ser_json_bytes: 'utf8'), serializing bytes that are not valid UTF-8 will raise aPydanticSerializationError. Use'base64'or'hex'for arbitrary binary data. - Configuration Precedence: The
ser_json_temporalsetting overridesser_json_timedelta. If you want specific behavior for timedeltas while keeping other temporal types as ISO8601, ensureser_json_temporalis not set. - Microseconds Precision: For
TimeSchema,DatetimeSchema, andTimedeltaSchema, themicroseconds_precisiondefaults to'truncate'. You can set it to'error'to fail if precision would be lost. - Dictionary Key Strings: In JSON mode, dictionary keys must be strings. Temporal keys will be converted to their string representation (ISO8601 or numeric string) regardless of the underlying value serialization format.