Time_until reports one hour more than expected before DST change

Daylight Saving Time will be introduced tonight and I noted that my markdown card displays 6 hours until 6AM when local time is now midnight. After 1:59, clock will turn to 3:00, so I expected the sensor to report 5 hours to 6 AM.

Here is my test in template editor. The input data appears to be time zone aware so why doesn’t time_until take care of this?

{# Testing "time_until" function 
{# Next time 06:00 #}
{% set next6am =(now()+timedelta(hours=18)).replace(hour=6, minute=0,second=0,microsecond=0) %}
{# Check that the time is correct and has time zone +2 #}
{{next6am}}  {# prints correctly: 2026-03-29 06:00:00+02:00 #}

{# Check that current time is correct and time zone +1 #}
{{now()}}   {# prints correctly: 2026-03-29 00:04:43.348178+01:00 #}

{{time_until(next6am)}}  {# prints incorrectly: 6 hours. I expected 5 hours. #}

I think you have hit one of the mind bending issues with tinezones.
There is actually 6 hours between the two points in time. One hour just goes extremely fast.

This is why computer systems internally work with UTC times and convert to local times only when presenting the value to the user, including HA.
My suggestion is to convert to UTC in your calculations.

Did you stay up to watch it click over?

That’s a sweet way to tell that the function is f-ed up :slightly_smiling_face:

The basic operation of time_until() relates to how Python manages the time difference between datetime objects.

In short, operations between two datetimes in the same timezone use “wall time” calculations, whereas operations between two datetimes in different timezones use “absolute time” semantics.

This shows up where we perform an operation to add “1 day” to a datetime. If the datetime is 06:00 in the morning, adding 1 day ends up at 06:00 tomorrow. The operation applies regardless of DST, and effectively means that “this time tomorrow” is “this time tomorrow”.

This blog post covers the Python behaviour in detail

Since time_delta retains the same timezone, all operations to add time will move forwards on “wall time” and therefore 6 hours after midnight will be 06:00, always, and the time between midnight and 06:00 will be 6 hours.

If you like, similar semantic aberrations occur with adding one month to the dates 29, 30 and 31st of each month. One month on from Jan 31 is not Feb 31 but Feb 28. Adding one year to Feb 29th is not possible, but we still manage to have birthdays and count ages.

Since time is a relative not absolute concept, and since DST introduces a step function to otherwise contiguous progression, there are many ways to cope and each language (where date-time is computed) will potentially use different approaches.

As Wally says, there are 6 hours between midnight and 06:00, because 06:00 - 00:00 = 6 hours.

It is not the function that is weird, it is the entire DST.
Around Europe and probably also in other places trains will actually get cancel and delayed for trains when DST set in, due to the loss of one hour and when DST is cancelled again trains will stand still for one hour to not arrive early.

https://travelswithkev.com/amtrak-daylight-saving-time/