Elapsed time between two sensor state changes

I have the template sensors below:

  - trigger: 
      - platform: state
        entity_id:
          - binary_sensor.engine_running_27_36
        to: 'on'
    sensor:
      - name: "Engine last started"
        icon: mdi:clock
        unique_id: engine_last_started
        state: "{{ now().strftime('%H:%M %d/%m/%Y') }}"

and

  - trigger: 
      - platform: state
        entity_id:
          - binary_sensor.engine_running_27_36
        to: 'off'
    sensor:
      - name: "Engine last stopped"
        icon: mdi:clock
        unique_id: engine_last_stopped
        state: "{{ now().strftime('%H:%M %d/%m/%Y') }}"

I’ve been trying to create a third sensor that returns the difference between the above two sensors, thereby showing the run time in the front end.

I’ve been playing with strptime and strftime in the template tools without success.

Please could somebody kindly point me in the right direction?

I thought there was an extensive thread on time calculations. I may, of course, have imagined that. Either way I can’t now find it.

You don’t have to compare these sensors (though you could) because the time of the last change is available as part of the trigger. Add a second sensor to the stopped one to store the runtime. To get the runtime in seconds, it would look something like:

- trigger: 
      - platform: state
        entity_id:
          - binary_sensor.engine_running_27_36
        to: 'off'
    sensor:
      - name: "Engine last stopped"
        icon: mdi:clock
        unique_id: engine_last_stopped
        state: "{{ now().strftime('%H:%M %d/%m/%Y') }}"
    sensor:
      - name: "Engine runtime"
        unique_id: engine_runtime
        state: "{{ as_timestamp(now()) - as_timestamp(trigger.from_state.last_changed) }}"

But if you really did want to create a template sensor that compares two timestamp strings using your format, the template should be something like (again this gives a result in seconds):

{% set start = states('sensor.engine_last_started') %}
{% set stop = states('sensor.engine_last_stopped') %}
{{ as_timestamp(strptime(stop, '%H:%M %d/%m/%Y')) - as_timestamp(strptime(start '%H:%M %d/%m/%Y')) }}

Thank you so much for your help. Really excellent.

That’s got me in the right direction. I appreciate your time.

I’ve been testing this and am getting some odd results when the times are spread over midnight and into the next day.

Should this be calculating using seconds since 1970 (which I think is when the clock started)? If that is the case then a day, or days change shouldn’t be an issue.

Here’s my config:

{% set start = states('sensor.engine_last_started') %}
{% set stop = states('sensor.engine_last_stopped') %}
{{ (( as_timestamp(strptime(stop, '%H:%M %d/%m/%Y')) - as_timestamp(strptime(start, '%H:%M %d/%m/%Y')) )|int|timestamp_custom('%H:%M', false)) }}

Any insights?

Can you describe the strange results? When I tried your approach, it worked fine unless start was more than 24 hours before stop, because you are purposely only showing the hours/minutes, not the days.

If you need to account for this use case, then you could consider using a timedelta instead. I put this in my template editor on the dev tools page:

{% set x = "16:28 11/03/2024" %}
{% set y = "10:22 10/03/2024" %}

{{ (( (as_timestamp(strptime(x, '%H:%M %d/%m/%Y')) - as_timestamp(strptime(y, '%H:%M %d/%m/%Y'))) ))  | int |timestamp_custom('%H:%M', false) }}
{{ timedelta( seconds=(as_timestamp(strptime(x, '%H:%M %d/%m/%Y')) - as_timestamp(strptime(y, '%H:%M %d/%m/%Y'))) ) }}

The first one is yours, the second one is modified to use timedelta. The results are:

1 day, 6:06:00
06:06

Thank you for taking the time with this. That’s just what I needed.

It was, indeed, a case of tracking over 24 hours.

I appreciate it.