Now()timestamp() incorrect

One of my binary sensors I found from a user here used to work. At some point, it stopped working properly. Not sure if it is from one of the updates (now on 2021.1.5) or a snapshot I install due to a faulty sd card on my rpi3. I think the cause is the now().timestamp()?

In HA, when I check

{% set t = now().timestamp() %}
t = 1612241382.0

I convert 1612241382 using using an unix converter online and it shows that it is 9hrs behind my actual time zone. Are both suppose to be the same?

GMT: Tuesday, February 2, 2021 4:49:42 AM
Your time zone: Tuesday, February 2, 2021 1:49:42 PM GMT+09:00

My config file for time zone is set correctly.

  name: Home
  latitude: !secret home_latitude
  longitude: !secret home_longitude
  elevation: 200
  unit_system: metric
  time_zone: Asia/Tokyo

This is the binary sensor in question. When I set the on and off input_datetime time within the range on the am hours, it never becomes true. Though it set to true about 9 hours later.

    friendly_name: "AM Time Active"
    value_template: >-
      {% set d = now().strftime("%Y-%m-%d ") %}
      {% set t = now().timestamp() %}
      {% set am_start = strptime(d + states('input_datetime.am_on_time'), '%Y-%m-%d %H:%M:%S').timestamp() %}
      {% set am_end = strptime(d + states('input_datetime.am_off_time'), '%Y-%m-%d %H:%M:%S').timestamp() %}
      {{ am_start <= t <= am_end }}

Asia/Tokyo time zone is UTC + 09:00 so now().timestamp() gives you UTC time.

Check out

{{ utcnow() }}
{{ now() }}
{{ utcnow().astimezone() }}
{{ now().astimezone() }}
{{ utcnow().tzinfo }}
{{ now().tzinfo }}
{{ now().astimezone().tzinfo }}

I don’t know what serves your need best.

Out of the list, the closes would be now(), but I don’t know how to convert it to seconds. Staring at the code some more, I came up with this substitute which seems to work. Though I would like to know why it had stopped working with the original code I had in the first place. The timezone of Asia/Tokyo has always been set from the time of installation of HA.

{% set t = strptime(d + states('sensor.time'), '%Y-%m-%d %H:%M').timestamp() %}

Timestamp is Unix time, I would be surprised if it was not in the past.

But you can convert unix to string or the other way around

This makes no sense. You use sensor.time which does not have a date and try and force a date to it.

That makes perfect sense if he wants to use sensor.time. Because a timestamp with just a HH:MM:SS does not return a timestamp from the ‘beginning of time’. However, this will force striptime to treat the time as unix time instead of his local timezone.

@duceduc the problem with your template is that strptime treats ALL incoming time strings as unix time. now().timestamp() is already correct, but your strptimes will be 9 hours ahead. You can fix this by moving everything to the same time. It’s easier to do this on your am_start and am end. Also, I’d just use as_timestamp() because it has a few more checks built into it that .timestamp() doesn’t. Also, you can just use a universal timestring with it without converting to a datetime object.

      {% set d = now().strftime("%Y-%m-%dT") %}
      {% set tz = as_timestamp(now()) | timestamp_custom('%z') %}
      {% set t = now().timestamp() %}
      {% set am_start = as_timestamp(d ~ states('input_datetime.am_on_time') ~ tz) %}
      {% set am_end = as_timestamp(d ~ states('input_datetime.am_off_time') ~ tz) %}
      {{ am_start <= t <= am_end }}

Your other option is to use unix time for everything, which what you did will solve.

      {% set d = now().strftime("%Y-%m-%d ") %}
      {% set t = strptime(d + states('sensor.time'), '%Y-%m-%d %H:%M').timestamp() %}
      {% set am_start = strptime(d + states('input_datetime.am_on_time'), '%Y-%m-%d %H:%M:%S').timestamp() %}
      {% set am_end = strptime(d + states('input_datetime.am_off_time'), '%Y-%m-%d %H:%M:%S').timestamp() %}
      {{ am_start <= t <= am_end }}

lastly, you can just simplify option 2 and omit the date because it doesn’t matter what date it is, just the time matters. And you can remove the timestamps because you can compare datetimes.

      {% set t = strptime(states('sensor.time'), '%H:%M') %}
      {% set am_start = strptime(states('input_datetime.am_on_time'), '%H:%M:%S') %}
      {% set am_end = strptime(states('input_datetime.am_off_time'), '%H:%M:%S') %}
      {{ am_start <= t <= am_end }}

And if you want to be SUPER lazy… You can simplify this even more by adding seconds to sensor.time

      {% set t = states('sensor.time') ~ ':00' %}
      {% set am_start = states('input_datetime.am_on_time') %}
      {% set am_end = states('input_datetime.am_off_time') %}
      {{ am_start <= t <= am_end }}

Which can be further reduced to a 1 liner:

      {{ states('input_datetime.am_on_time') <= states('sensor.time') ~ ':00'  <= states('input_datetime.am_off_time') }}