mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 15:31:52 -05:00
Add timedelta_string template function similar to time_since/time_until/relative_time (#169773)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI
parent
7c9cc36a6d
commit
1d9ae4b184
@@ -117,6 +117,14 @@ class DateTimeExtension(BaseTemplateExtension):
|
||||
requires_hass=True,
|
||||
limited_ok=False,
|
||||
),
|
||||
TemplateFunction(
|
||||
"timedelta_string",
|
||||
self.timedelta_string,
|
||||
as_global=True,
|
||||
as_filter=True,
|
||||
requires_hass=True,
|
||||
limited_ok=False,
|
||||
),
|
||||
TemplateFunction(
|
||||
"today_at",
|
||||
self.today_at,
|
||||
@@ -319,3 +327,19 @@ class DateTimeExtension(BaseTemplateExtension):
|
||||
If the value not a datetime object the input will be returned unmodified.
|
||||
"""
|
||||
return self._datetime_as_string(value, precision=precision, future=True)
|
||||
|
||||
def timedelta_string(self, value: Any, precision: int = 1) -> Any:
|
||||
"""Take a timedelta and return a human-readable string representation.
|
||||
|
||||
The result can be in seconds, minutes, hours, days, months and years.
|
||||
|
||||
precision is the number of units to return, with the last unit rounded.
|
||||
precision=0 returns all units (no early rounding, except for sub-second values).
|
||||
|
||||
Negative timedeltas are formatted using their absolute value.
|
||||
|
||||
If the value is not a timedelta object the input will be returned unmodified.
|
||||
"""
|
||||
if not isinstance(value, timedelta):
|
||||
return value
|
||||
return dt_util.timedelta_string(value, precision)
|
||||
|
||||
@@ -387,6 +387,20 @@ def get_time_remaining(date: dt.datetime, precision: int = 1) -> str:
|
||||
return _get_timestring(rounded_delta, precision)
|
||||
|
||||
|
||||
def timedelta_string(delta: dt.timedelta, precision: int = 1) -> str:
|
||||
"""Return a string representation of a timedelta.
|
||||
|
||||
The result can be in seconds, minutes, hours, days, months and years.
|
||||
|
||||
precision is the number of units to return, with the last unit rounded.
|
||||
precision=0 returns all units (no early rounding, except for sub-second values).
|
||||
|
||||
Negative timedeltas are treated as their absolute value.
|
||||
"""
|
||||
rounded_delta = round(abs(delta.total_seconds()))
|
||||
return _get_timestring(rounded_delta, precision)
|
||||
|
||||
|
||||
def parse_time_expression(parameter: Any, min_value: int, max_value: int) -> list[int]:
|
||||
"""Parse the time expression part and return a list of times to match."""
|
||||
if parameter is None or parameter == "*":
|
||||
|
||||
@@ -786,3 +786,35 @@ async def test_time_until(mock_is_safe, hass: HomeAssistant) -> None:
|
||||
|
||||
info = render_to_info(hass, time_until_template)
|
||||
assert info.has_time is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("template_str", "expected"),
|
||||
[
|
||||
("{{ timedelta(seconds=0) | timedelta_string }}", "0 seconds"),
|
||||
("{{ timedelta(seconds=1) | timedelta_string }}", "1 second"),
|
||||
("{{ timedelta(hours=1) | timedelta_string }}", "1 hour"),
|
||||
("{{ timedelta(hours=2) | timedelta_string }}", "2 hours"),
|
||||
("{{ timedelta(hours=1, minutes=30) | timedelta_string }}", "2 hours"),
|
||||
(
|
||||
"{{ timedelta(hours=1, minutes=30) | timedelta_string(precision=2) }}",
|
||||
"1 hour 30 minutes",
|
||||
),
|
||||
(
|
||||
"{{ timedelta(hours=1, minutes=54, seconds=33) | timedelta_string(precision=3) }}",
|
||||
"1 hour 54 minutes 33 seconds",
|
||||
),
|
||||
(
|
||||
"{{ timedelta(hours=1, minutes=54, seconds=33) | timedelta_string(precision=0) }}",
|
||||
"1 hour 54 minutes 33 seconds",
|
||||
),
|
||||
("{{ timedelta_string(timedelta(hours=1), precision=2) }}", "1 hour"),
|
||||
("{{ timedelta_string('string') }}", "string"),
|
||||
("{{ timedelta_string(42) }}", 42),
|
||||
],
|
||||
)
|
||||
def test_timedelta_string(
|
||||
hass: HomeAssistant, template_str: str, expected: str | int
|
||||
) -> None:
|
||||
"""Test timedelta_string function and filter."""
|
||||
assert render(hass, template_str) == expected
|
||||
|
||||
@@ -292,6 +292,34 @@ def test_time_remaining() -> None:
|
||||
assert dt_util.get_time_remaining(diff) == "1 year"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("delta", "precision", "expected"),
|
||||
[
|
||||
(timedelta(seconds=0), 1, "0 seconds"),
|
||||
(timedelta(milliseconds=400), 1, "0 seconds"),
|
||||
(timedelta(milliseconds=600), 1, "1 second"),
|
||||
(timedelta(seconds=1), 1, "1 second"),
|
||||
(timedelta(seconds=30), 1, "30 seconds"),
|
||||
(timedelta(minutes=1), 1, "1 minute"),
|
||||
(timedelta(minutes=5), 1, "5 minutes"),
|
||||
(timedelta(hours=1), 1, "1 hour"),
|
||||
(timedelta(hours=5), 1, "5 hours"),
|
||||
(timedelta(hours=1, minutes=30), 1, "2 hours"),
|
||||
(timedelta(hours=1, minutes=30), 2, "1 hour 30 minutes"),
|
||||
(timedelta(days=2), 1, "2 days"),
|
||||
(timedelta(days=32), 1, "1 month"),
|
||||
(timedelta(days=365), 1, "1 year"),
|
||||
(timedelta(hours=1, minutes=54, seconds=33), 3, "1 hour 54 minutes 33 seconds"),
|
||||
(timedelta(hours=1, minutes=54, seconds=33), 0, "1 hour 54 minutes 33 seconds"),
|
||||
(timedelta(hours=-1), 1, "1 hour"),
|
||||
(timedelta(hours=-1, minutes=-30), 2, "1 hour 30 minutes"),
|
||||
],
|
||||
)
|
||||
def test_timedelta_string(delta: timedelta, precision: int, expected: str) -> None:
|
||||
"""Test timedelta_string."""
|
||||
assert dt_util.timedelta_string(delta, precision) == expected
|
||||
|
||||
|
||||
def test_parse_time_expression() -> None:
|
||||
"""Test parse_time_expression."""
|
||||
assert list(range(60)) == dt_util.parse_time_expression("*", 0, 59)
|
||||
|
||||
Reference in New Issue
Block a user