How do I set a timestamp helper in UTC but then use it for local time calculations?

With some help I’ve managed to perform some time calculations with helpers and they now work as expected when changed in the dashboard. I’d like to be able to set a helper to the time my current energy supplier changes from cheap to expensive energy. This can change when changing supplier so I want to use a helper just to make life easier. The time this happens is set in UTC, it does not change with daylight savings, which is plus 1 hour for me.

However, I’m stumped on how I can set a time in a helper that is in UTC. I can set this value in local and change to UTC, but I can’t see an obvious way to flag this as UTC and then calculate local.

I’d like the helper input_datetime.economy_7_off_time_utc to be set, or calculated, as UTC in the following automation. To me it looks like as soon as I do anything with the helper the result is local, I haven’t yet found a simple way to keep it as UTC?

service: input_datetime.set_datetime
target:
  entity_id: input_datetime.heated_towel_rail_on_time
data:
  timestamp: >-
    {{ (today_at(states('input_datetime.economy_7_off_time_utc')) -
    (as_timedelta(states('input_datetime.heated_towel_rail_on_hours'))).timestamp())
    }}

As with previous queries, it’s usually a straighforward solution but it’s currently eluding me.

Assuming your datetime only has a time and not a date as well, try this in the template editor:

{{state_attr('input_datetime.economy_7_off_time_utc','timestamp')|timestamp_custom('%H:%M:%S', local=True) }}

So, trying to understand how this string is generated… state_attr confirms my helper is a timestamp, then timestamp_custom strips out the time with '%H:%M' and local=True converts to local. Therefore somewhere there’s an assumption the helper is UTC?

I can then convert this string to a timestamp and do my calculation?

The template does not use the helper state. Each input date time helper has a timestamp attribute (Look at the attributes in dev tools / states). This is referenced to the Unix epoch if no date is included.

The template converts this attribute to a HH:MM:SS string in UTC.

Yes you can then use this in your calculation. You will probably have to convert it to a datetime object or timestamp before doing any math.

The confusing bit is the option local=true.

How timestamp_custom outputs depends on this setting AND if the helper has a date or not. See this post by Phil: Input datetime automation wrong time? - #5 by pnbruckner

This has tripped me up many times. I now just check it in the developer tools template editor every time I use it.

Thank you, I think :crazy_face: My simple calculation of taking a Unix time subtracting an offset is taking on a WHOLE new aspect of learning, confusion and exasperation.

A positive learning experience though. I don’t remember time calculations being this difficult back in the day when I used to do this in C. Seems like a lot of type casting :thinking:

Some time to be spent in template editor I think…

Finally with some time spent in template editor, I set a time helper to when my cheap energy finishes, this time is in GMT/UTC, this will only change if my supplier changes and this time is changed. I set another helper that specifies how long I (the Mrs tells me) wants the rail to be on. This formula then work out the time, in local, taking into account daylight savings, BST for me. This template seems VERY complicated for what I thought was going to be a straightforward process.

Anyway, if anybody else encounters a similar issue here’s the solution I’ve arrived at with help and hopefully it will help others. OR, if someone has a simpler more eligant solution I’m (really) open to ideas!

service: input_datetime.set_datetime
target:
  entity_id: input_datetime.heated_towel_rail_on_time
data:
  timestamp: |-
    {{ (
      today_at(state_attr('input_datetime.economy_7_off_time_utc','timestamp') |
        timestamp_custom('%H:%M:%S', local=True)) -
      as_timedelta(states('input_datetime.heated_towel_rail_on_hours'))
    ).timestamp() }}