Skip to content

DateTime

SUMMARY

An absolute timezone-aware wall-clock datetime.

python
from datetime import datetime, timezone

from telekinesis import datatypes
value = datatypes.DateTime(datetime.now(timezone.utc))

Parameters

FieldTypeDescription
datadatetime.datetimeA timezone-aware datetime, normalized to UTC on storage. Intended for metadata such as created_at/updated_at/deleted_at. Unlike Timestamp, DateTime has timezone semantics rather than an arbitrary clock epoch.

Raises

ExceptionCondition
TypeErrordata is not a datetime.datetime
ValueErrordata is naive (tzinfo is None, or utcoffset() is None)

Attributes

AttributeTypeDescription
datadatetime.datetimeThe wrapped value, converted to UTC (tzinfo=timezone.utc) via astimezone. Since datetime.datetime is immutable, no copying is ever required — reading data returns the normalized value directly. Assigning a new value re-validates and re-normalizes it the same way as construction.

Methods

MethodDescription
DateTime.coerce(value, name="value")Returns value unchanged if it's already a DateTime; otherwise wraps a timezone-aware datetime.datetime. name sets the label used to identify the value in a raised error message. Raises TypeError if value is neither a DateTime nor a datetime.datetime, or ValueError if it's a naive datetime.datetime.

Operators

OperationReturns
a == bbool
a != bbool
a < bbool
a > bbool

==/< accept a DateTime or a datetime.datetime on the right-hand side; comparing against a naive datetime.datetime raises ValueError rather than returning False/NotImplemented, since normalization is attempted before comparing. > works only through Python's automatic reflected fallback to __lt__ — there is no explicit __gt__. <= and >= are intentionally not implemented and raise TypeError. Because .data is a real datetime.datetime, arithmetic like value.data - other_datetime works directly through Python's datetime API and returns a timedelta. Not hashable (__hash__ is None) — data is mutable via its setter.

Visualization

datatypes.visualize(value, entity_path=...) renders the value as text — the human-readable UTC form (e.g. "2026-08-06 12:34:56.789012+00:00"), rather than a numeric epoch.

Example

python
"""Demonstrates the Telekinesis DateTime datatype."""

import time
from datetime import datetime, timedelta, timezone

import rerun as rr
from loguru import logger

from telekinesis import datatypes

def datetime_example():
    """Demonstrate creation, inspection, operations, visualization, and serialization."""

    # ======================= Create ============================================
    created_at = datatypes.DateTime(datetime.now(timezone.utc))
    logger.info(f"Created DateTime: {created_at}")

    coerced = datatypes.DateTime.coerce(datetime.now(timezone.utc))
    logger.info(f"DateTime coerced from datetime: {coerced}")

    # ======================= Inspect ===========================================
    logger.info(f"data={created_at.data}")

    # ======================= Operations ========================================
    created_at.data = created_at.data + timedelta(minutes=5)
    logger.info(f"Updated DateTime: {created_at}")

    # Any timezone-aware datetime is accepted; it is normalized to UTC on storage.
    pst = datatypes.DateTime(datetime.now(timezone(timedelta(hours=-8))))
    logger.info(f"DateTime from PST input, normalized to UTC: {pst}")

    earlier = datatypes.DateTime(created_at.data - timedelta(minutes=1))

    logger.info(f"EQ: {created_at} == {created_at} = {created_at == created_at}")
    logger.info(f"LT: {earlier} < {created_at} = {earlier < created_at}")
    logger.info(f"GT (via reflected __lt__): {created_at} > {earlier} = {created_at > earlier}")

    # ======================= Visualize =========================================
    rr.init("datetime_example", spawn=True)
    datatypes.visualize(created_at, entity_path="/datetime/updated")
    datatypes.visualize(pst, entity_path="/datetime/pst")

    # ======================= Serialize / Deserialize ===========================
    start = time.perf_counter()
    serialized = datatypes.serialize(created_at)
    serialization_ms = (time.perf_counter() - start) * 1000

    start = time.perf_counter()
    deserialized = datatypes.deserialize(serialized)["param_0"]
    deserialization_ms = (time.perf_counter() - start) * 1000

    logger.info(f"Deserialized DateTime: {deserialized}")
    logger.info(f"Round-trip successful: {created_at == deserialized}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")


if __name__ == "__main__":
    datetime_example()