Source code for bokeh.core.property.datetime

#-----------------------------------------------------------------------------
# Copyright (c) 2012 - 2023, Anaconda, Inc., and Bokeh Contributors.
# All rights reserved.
#
# The full license is in the file LICENSE.txt, distributed with this software.
#-----------------------------------------------------------------------------
""" Provide date and time related properties

"""

#-----------------------------------------------------------------------------
# Boilerplate
#-----------------------------------------------------------------------------
from __future__ import annotations

import logging # isort:skip
log = logging.getLogger(__name__)

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

# Standard library imports
import datetime
from typing import Any, Union

# Bokeh imports
from ...util.serialization import convert_date_to_datetime, is_datetime_type, is_timedelta_type
from .bases import Init, Property
from .primitive import bokeh_integer_types
from .singletons import Undefined

#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------

__all__ = (
    'Date',
    'Datetime',
    'Time',
    'TimeDelta',
)

#-----------------------------------------------------------------------------
# General API
#-----------------------------------------------------------------------------

[docs]class Date(Property[Union[str, datetime.date]]): """ Accept ISO format Date (but not DateTime) values. """ def transform(self, value: Any) -> Any: value = super().transform(value) if isinstance(value, datetime.date): value = value.isoformat() return value def validate(self, value: Any, detail: bool = True) -> None: super().validate(value, detail) # datetime.datetime is datetime.date, exclude manually up front if isinstance(value, datetime.datetime): msg = "" if not detail else "Expected a date value, got a datetime.datetime" raise ValueError(msg) if isinstance(value, datetime.date): return try: datetime.datetime.fromisoformat(value) except Exception: msg = "" if not detail else f"Expected an ISO date string, got {value!r}" raise ValueError(msg)
[docs]class Datetime(Property[Union[str, datetime.date, datetime.datetime]]): """ Accept ISO format Datetime values. """ def __init__(self, default: Init[str | datetime.date | datetime.datetime] = Undefined, *, help: str | None = None) -> None: super().__init__(default=default, help=help) def transform(self, value: Any) -> Any: value = super().transform(value) if isinstance(value, str): value = datetime.datetime.fromisoformat(value) # Handled by serialization in protocol.py for now, except for Date if isinstance(value, datetime.date): value = convert_date_to_datetime(value) return value def validate(self, value: Any, detail: bool = True) -> None: super().validate(value, detail) if is_datetime_type(value): return if isinstance(value, datetime.date): return if Datetime.is_timestamp(value): return if isinstance(value, str): try: datetime.datetime.fromisoformat(value).date() return except Exception: pass msg = "" if not detail else f"Expected a date, datetime object, or timestamp, got {value!r}" raise ValueError(msg) @staticmethod def is_timestamp(value: Any) -> bool: return isinstance(value, (float,) + bokeh_integer_types) and not isinstance(value, bool)
[docs]class Time(Property[Union[str, datetime.time]]): """ Accept ISO format time values. """ def __init__(self, default: Init[str | datetime.time] = Undefined, *, help: str | None = None) -> None: super().__init__(default=default, help=help) def validate(self, value: Any, detail: bool = True) -> None: super().validate(value, detail) if isinstance(value, datetime.time): return if isinstance(value, str): try: datetime.time.fromisoformat(value) return except ValueError: pass msg = "" if not detail else f"Expected a time object, or ISO formatted time string, got {value!r}" raise ValueError(msg) def transform(self, value: Any) -> Any: value = super().transform(value) if isinstance(value, str): value = datetime.time.fromisoformat(value) return value
[docs]class TimeDelta(Property[datetime.timedelta]): """ Accept TimeDelta values. """ def __init__(self, default: Init[datetime.timedelta] = datetime.timedelta(), *, help: str | None = None) -> None: super().__init__(default=default, help=help) def transform(self, value: Any) -> Any: value = super().transform(value) return value # Handled by serialization in protocol.py for now def validate(self, value: Any, detail: bool = True) -> None: super().validate(value, detail) if is_timedelta_type(value): return msg = "" if not detail else f"Expected a timedelta instance, got {value!r}" raise ValueError(msg)
#----------------------------------------------------------------------------- # Dev API #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Private API #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Code #-----------------------------------------------------------------------------