Skip to main content

Temporal and Network Types

The pydantic-core library provides a robust set of schemas for validating and parsing temporal data (dates, times, durations), unique identifiers (UUIDs), and network addresses (URLs). These schemas go beyond simple type checking by offering range constraints, timezone enforcement, and specialized parsing for complex string formats like ISO-8601.

Temporal Types

Temporal validation in this codebase is handled by four primary schemas: DateSchema, TimeSchema, DatetimeSchema, and TimedeltaSchema. These schemas support validation from Python objects, ISO-8601 strings, and, in the case of dates and datetimes, Unix timestamps.

Date and Datetime Validation

DateSchema and DatetimeSchema share several common features, including range constraints and relative time checks.

  • Range Constraints: You can enforce bounds using le (less than or equal), lt (less than), ge (greater than or equal), and gt (greater than).
  • Relative Checks: The now_op field allows for 'past' or 'future' validation relative to the current time. This is often paired with now_utc_offset to handle local time differences.
  • Timezone Enforcement: DatetimeSchema includes a tz_constraint which can be set to 'aware', 'naive', or a specific integer offset in seconds.

As seen in pydantic-core/tests/validators/test_date.py, dates can be validated from strings, integers (as Unix timestamps), or even datetime objects if the time component is exactly midnight:

from datetime import date
from pydantic_core import SchemaValidator, core_schema

# Define a schema with range constraints
schema = core_schema.date_schema(ge=date(2020, 1, 1), le=date(2025, 12, 31))
v = SchemaValidator(schema)

# Validates from ISO-8601 string
assert v.validate_python('2023-05-15') == date(2023, 5, 15)

# Validates from Unix timestamp
assert v.validate_python(1654646400) == date(2022, 6, 8)

Time and Timedelta

TimeSchema and TimedeltaSchema handle clock times and durations respectively.

  • Microsecond Precision: Both schemas support microseconds_precision, which can be set to 'truncate' (default) or 'error'. If set to 'error', validation fails if the input contains sub-microsecond precision that would be lost.
  • Timedelta Formats: TimedeltaSchema validates Python timedelta objects, numeric values (interpreted as seconds), and ISO-8601 duration strings (e.g., 'P3DT1H').
from datetime import time
from pydantic_core import SchemaValidator, core_schema

# Time schema with timezone awareness requirement
schema = core_schema.time_schema(tz_constraint='aware')
v = SchemaValidator(schema)

# Validates string with offset
result = v.validate_python('12:30:00+05:00')
assert result.utcoffset().total_seconds() == 18000

Identifier Types

The UuidSchema provides validation for Universally Unique Identifiers. It supports validation from uuid.UUID objects, hex strings, and raw bytes.

A key feature of UuidSchema is the ability to enforce specific UUID versions (1, 3, 4, 5, or 7) via the version field. This is implemented in pydantic-core/python/pydantic_core/core_schema.py and tested in pydantic-core/tests/validators/test_uuid.py.

from pydantic_core import SchemaValidator, core_schema

# Enforce UUID version 4
v = SchemaValidator(core_schema.uuid_schema(version=4))

# Valid version 4 UUID
v.validate_python('0e7ac198-9acd-4c0c-b4b4-761974bf71d7')

# Version 1 UUID will raise ValidationError
# v.validate_python('a6cc5730-2261-11ee-9c43-2eb5a363657c')

Network Types

Network validation is centered around UrlSchema and MultiHostUrlSchema. Unlike simple string types, these return specialized Url and MultiHostUrl objects that provide structured access to URL components.

URL Parsing and Constraints

UrlSchema allows for fine-grained control over what constitutes a valid URL:

  • Allowed Schemes: Restrict URLs to specific protocols like ['http', 'https'].
  • Host Requirements: Use host_required=True to ensure the URL isn't just a path.
  • Default Components: You can specify default_host, default_port, and default_path to fill in missing information during parsing.

The resulting Url object, as demonstrated in pydantic-core/tests/validators/test_url.py, exposes attributes for easy access:

from pydantic_core import SchemaValidator, core_schema

v = SchemaValidator(core_schema.url_schema(allowed_schemes=['https']))
url = v.validate_python('https://user:pass@example.com:8080/path?query=1#frag')

assert url.scheme == 'https'
assert url.host == 'example.com'
assert url.port == 8080
assert url.path == '/path'
assert url.username == 'user'
assert url.query_params() == [('query', '1')]

Multi-Host URLs

MultiHostUrlSchema is designed for connection strings that support multiple endpoints, such as database clusters (e.g., postgres://host1:5432,host2:5432/db). It returns a MultiHostUrl object which contains a list of MultiHostHost objects, each representing an individual host/port pair.

Configuration Options

The behavior of these types can be influenced by CoreConfig:

  • url_preserve_empty_path: By default, pydantic-core may normalize empty paths (e.g., http://example.com becomes http://example.com/). Setting this to True preserves the original path state.
  • ser_json_temporal: Controls how temporal types are serialized to JSON (defaults to 'iso8601').
  • ser_json_timedelta: Specifically controls timedelta serialization (defaults to 'iso8601').