I wanted to add the time till sunset to my overview screen.
With many examples around, I thought it would be easy.
However… The calculated time is off by 1 hour.
Most times are cast to UTC, you are an hour out so I’m assuming you are in Europe (UK specifically ???) , but we are out of DST so I’m not sure why you raise this now, where they are synchronous.
Regardless, due to the default cast to UTC, I think what you need is : -
That will work because the sun component (by default) gives local times for sun events.
You are specifically requesting UTC times, so the comparison is direct.
But it’s a long winded way of doing it, just convert the offset to local.
The following begins by converting next_setting from a string value to an offset-aware datetime object.
The conversion is complicated by the fact that +00:00 is not understood to be a timezone offset by strptime’s %z because it prefers +0000. So we tack it on to accommodate it.
After it’s been converted, the calculation is straightforward because now we have two datetime objects, the next sunset and the current time, and both are in UTC.
{% set nr = strptime(state_attr('sun.sun', 'next_setting')~'+0000', '%Y-%m-%dT%H:%M:%S+00:00%z') %}
Next Setting (UTC): {{ nr }}
Current time (UTC): {{ utcnow() }}
Difference:
As a timedelta object: {{ nr - utcnow() }}
As a string: {{ (nr.timestamp() - utcnow().timestamp()) | timestamp_custom('%-H:%M', false) }}
I had previously used the template examples above to calculate the time until the next sunset/sunrise. But a change in HA at some point has broken this. I’m guessing it was one of the more major Python version bumps.
The time format returned is no longer in '%Y-%m-%dT%H:%M:%S+00:00%z' but rather '%Y-%m-%dT%H:%M:%S.%f+00:00'. However, even making this change the delta values are no longer respecting the UTC/local difference and as a result the returned values are wrong.
Has anyone worked out how to fix this since it was broken by the update?
EDIT: I worked it out. See below for old (nr1) and new (nr2) syntax
{% set nr1 = strptime(state_attr('sun.sun', 'next_setting'), '%Y-%m-%dT%H:%M:%S.%f+00:00', 0) %}
{% set nr2 = as_datetime(state_attr('sun.sun', 'next_setting')) %}
nr1: {{ nr1 }}
nr2: {{ nr2 }}
utc: {{ utcnow() }}
Difference:
1. As a string: {{ (nr1.timestamp() - as_local(utcnow()).timestamp()) | timestamp_custom('%-H:%M', false) }}
2. As a string: {{ (nr2.timestamp() - as_local(utcnow()).timestamp()) | timestamp_custom('%-H:%M', false) }}
which prints out:
nr1: 2023-10-06 08:12:43.941101
nr2: 2023-10-06 08:12:43.941101+00:00
utc: 2023-10-06 06:54:00.151155+00:00
Difference:
1. As a string: 14:18
2. As a string: 1:18
Interesting!
As I understand it now, this was the problem at that time:
But as I understand it now, this has been solved since Python version 3.7, and +00:00 is now understood as well, making it possible to now do it like this (nr3 added):
{% set nr1 = strptime(state_attr('sun.sun', 'next_setting'), '%Y-%m-%dT%H:%M:%S.%f+00:00', 0) %}
{% set nr2 = as_datetime(state_attr('sun.sun', 'next_setting')) %}
{% set nr3 = strptime(state_attr('sun.sun', 'next_setting'), '%Y-%m-%dT%H:%M:%S.%f%z') %}
nr1: {{ nr1 }}
nr2: {{ nr2 }}
nr3: {{ nr3 }}
utc: {{ utcnow() }}
Difference:
1. As a string: {{ (nr1.timestamp() - as_local(utcnow()).timestamp()) | timestamp_custom('%-H:%M', false) }}
2. As a string: {{ (nr2.timestamp() - as_local(utcnow()).timestamp()) | timestamp_custom('%-H:%M', false) }}
3. As a string: {{ (nr3.timestamp() - as_local(utcnow()).timestamp()) | timestamp_custom('%-H:%M', false) }}
But your solution is more elegant and straight forward.