From e90d76b18de75d80c132cc3338b1ad44ed6f101c Mon Sep 17 00:00:00 2001 From: Martijn van der Pol Date: Tue, 23 Apr 2024 09:55:58 +0200 Subject: [PATCH] Don't raise errors when using datetime objects in `as_datetime` Jinja function/filter (#109062) * add support for datetime objects to as_datetime * change import of datetime.date --------- Co-authored-by: Erik Montnemery --- homeassistant/helpers/template.py | 14 ++++++++++---- tests/helpers/test_template.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 16379c1d05c..a1ba1279292 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -9,7 +9,7 @@ import collections.abc from collections.abc import Callable, Generator, Iterable from contextlib import AbstractContextManager, suppress from contextvars import ContextVar -from datetime import datetime, timedelta +from datetime import date, datetime, time, timedelta from functools import cache, lru_cache, partial, wraps import json import logging @@ -2001,12 +2001,12 @@ def square_root(value, default=_SENTINEL): def timestamp_custom(value, date_format=DATE_STR_FORMAT, local=True, default=_SENTINEL): """Filter to convert given timestamp to format.""" try: - date = dt_util.utc_from_timestamp(value) + result = dt_util.utc_from_timestamp(value) if local: - date = dt_util.as_local(date) + result = dt_util.as_local(result) - return date.strftime(date_format) + return result.strftime(date_format) except (ValueError, TypeError): # If timestamp can't be converted if default is _SENTINEL: @@ -2048,6 +2048,12 @@ def forgiving_as_timestamp(value, default=_SENTINEL): def as_datetime(value: Any, default: Any = _SENTINEL) -> Any: """Filter and to convert a time string or UNIX timestamp to datetime object.""" + # Return datetime.datetime object without changes + if type(value) is datetime: + return value + # Add midnight to datetime.date object + if type(value) is date: + return datetime.combine(value, time(0, 0, 0)) try: # Check for a valid UNIX timestamp string, int or float timestamp = float(value) diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 524b8f47dfe..ec5b76964f7 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -1198,6 +1198,35 @@ def test_as_datetime_from_timestamp( ) +@pytest.mark.parametrize( + ("input", "output"), + [ + ( + "{% set dt = as_datetime('2024-01-01 16:00:00-08:00') %}", + "2024-01-01 16:00:00-08:00", + ), + ( + "{% set dt = as_datetime('2024-01-29').date() %}", + "2024-01-29 00:00:00", + ), + ], +) +def test_as_datetime_from_datetime( + hass: HomeAssistant, input: str, output: str +) -> None: + """Test using datetime.datetime or datetime.date objects as input.""" + + assert ( + template.Template(f"{input}{{{{ dt | as_datetime }}}}", hass).async_render() + == output + ) + + assert ( + template.Template(f"{input}{{{{ as_datetime(dt) }}}}", hass).async_render() + == output + ) + + @pytest.mark.parametrize( ("input", "default", "output"), [