Skip to main content

Temporal Data Handling

Temporal data handling in pydantic-core is managed through four specialized schemas defined in pydantic_core.core_schema: DateSchema, TimeSchema, DatetimeSchema, and TimedeltaSchema. These schemas provide robust validation for Python's native datetime module types, supporting range constraints, timezone enforcement, and precision control.

Core Temporal Schemas​

The implementation relies on TypedDict structures that define the validation parameters for each type.

  • DateSchema: Validates datetime.date objects and compatible strings/integers.
  • TimeSchema: Validates datetime.time objects, supporting timezone and precision constraints.
  • DatetimeSchema: A comprehensive schema for datetime.datetime, combining features of both date and time validation.
  • TimedeltaSchema: Validates durations (datetime.timedelta), supporting ISO8601 duration strings and numeric (seconds) input.

Shared Comparison Constraints​

All four temporal schemas support standard comparison operators: le (less than or equal), ge (greater than or equal), lt (less than), and gt (greater than). These constraints must be of the same type as the schema (e.g., le in a DateSchema must be a datetime.date).

from datetime import date
from pydantic_core import SchemaValidator, core_schema

# Example: Date range validation
schema = core_schema.date_schema(le=date(2020, 1, 1), ge=date(2019, 1, 1))
v = SchemaValidator(schema)
assert v.validate_python(date(2019, 6, 1)) == date(2019, 6, 1)

Relative Validation with now_op​

DateSchema and DatetimeSchema support relative validation using the now_op field. This allows enforcing that a value is in the past or future relative to the moment of validation.

  • now_op: Either 'past' or 'future'.
  • now_utc_offset: An integer representing the UTC offset in seconds (defaults to the local system offset).

In pydantic-core/tests/validators/test_date.py, this is used to validate dates relative to the current time:

# Validating a date is in the past
v = SchemaValidator(core_schema.date_schema(now_op='past'))
# Fails for future dates
# v.validate_python('2068-06-08') -> ValidationError: Date should be in the past

Timezone Management​

TimeSchema and DatetimeSchema use the tz_constraint to enforce timezone requirements. This is critical for APIs that require consistent timezone handling.

  • 'aware': Requires the input to have timezone information.
  • 'naive': Requires the input to NOT have timezone information.
  • int: Requires a specific fixed UTC offset in seconds.

Example from pydantic-core/tests/validators/test_datetime.py:

# Enforcing timezone awareness
v = SchemaValidator(core_schema.datetime_schema(tz_constraint='aware'))
v.validate_python('2022-06-08T12:13:14Z') # Success
# v.validate_python('2022-06-08T12:13:14') -> ValidationError: Input should have timezone info

Precision Handling​

TimeSchema, DatetimeSchema, and TimedeltaSchema include a microseconds_precision setting to control how sub-microsecond data is handled.

  • 'truncate' (default): Silently drops any precision beyond microseconds.
  • 'error': Raises a ValidationError if the input contains more than 6 digits of fractional seconds.

Example from pydantic-core/tests/validators/test_time.py:

# Raising an error on excessive precision
v = SchemaValidator(core_schema.time_schema(microseconds_precision='error'))
# v.validate_python('00:00:00.1234567') -> ValidationError: second fraction value is more than 6 digits long

Duration Validation (TimedeltaSchema)​

The TimedeltaSchema is unique in its support for multiple input formats, including ISO8601 duration strings (e.g., P3DT1H) and numeric values interpreted as seconds.

from datetime import timedelta
from pydantic_core import SchemaValidator, core_schema

v = SchemaValidator(core_schema.timedelta_schema())

# ISO8601 string support
assert v.validate_python('P0Y0M3D2WT1H2M3.5S') == timedelta(days=17, hours=1, minutes=2, seconds=3, milliseconds=500)

# Numeric (seconds) support
assert v.validate_python(3601) == timedelta(hours=1, seconds=1)

Serialization Configuration​

Serialization behavior for temporal types is configured globally via CoreConfig or per-schema via SerSchema.

  • ser_json_temporal: Controls JSON output for all temporal types. Options include 'iso8601', 'seconds', and 'milliseconds'.
  • ser_json_timedelta: Specifically for timedelta. Options are 'iso8601' or 'float'. Note that this is ignored if ser_json_temporal is explicitly set.

These settings ensure that validated temporal objects are converted back to strings or numbers consistently during to_json() operations.

Common Validation Behaviors​

Date from Datetime​

When using DateSchema, validating a datetime object or string will succeed in lax mode (default) only if the time component is zero. If the time is non-zero, it is considered "inexact" and will fail unless strict=False is explicitly handled or the input is a pure date.

Numeric Limits​

TimedeltaSchema enforces internal limits on numeric inputs. For example, durations exceeding 999,999,999 days (or their equivalent in seconds) will trigger a validation error, as seen in pydantic-core/tests/validators/test_timedelta.py.