Relative_time including minutes?

I have an input_datetime sensor. I’m trying to create a template sensor that shows the relative time since the timestamp in the input_datetime sensor as “X hours and Y minutes ago”.

When using {{ relative_time(states.input_datetime.example.last_changed) }}, if it’s more than 1 hour since the timestamp, the output is simply 1 hour but I would like it to say how many minutes as well.

How can I accomplish this?

What is the output of this template in developer tools?

it may not be the most elegant but I think this will work:

{% set time_diff =  (as_timestamp(now()) - as_timestamp(states.input_datetime.example.last_changed)) | timestamp_custom('%H:%M')  %}
{{ time_diff.split(':')[0]}} Hours {{ time_diff.split(':')[1] }} Minutes

According to the docs the last time I looked I don’t think there is a way to get the output you want using relative_time()

That works great! But it’s off by 1 hour ( shows 1 hour and 10 minutes when it should only show 10 minutes). How can I correct that?

Probably because now() reports local time and as_timestamp does not.
Try them in the template tool and see what you get.

That’s what I did.

Maybe it will work if I put it in an actual template sensor.

EDIT: IT does not. Still off by 1 hour.

Anyone know?

try this instead:

{% set time_diff =  (as_timestamp(utcnow()) - as_timestamp(states.input_datetime.example.last_changed)) | timestamp_custom('%H:%M')  %}
{{ time_diff.split(':')[0]}} Hours {{ time_diff.split(':')[1] }} Minutes

That won’t work if the time is greater than 24 hours.

Here’s a calculation that works with any time difference.

For just hours and minutes, it would be:

          {%- set word_for_and = 'and' %}
          {%- set up_time = as_timestamp(utcnow())-as_timestamp(states.input_datetime.example.last_changed) %}

          {%- macro phrase(name, plural_name, divisor, mod=None) %}
            {%- set value = ((up_time // divisor) % (mod if mod else divisor)) | int %}
            {%- set name = plural_name if value > 1 else name %}
            {{- '{} {}'.format(value, name) if value | int > 0 else '' }}
          {%- endmacro %}
          {%- set values = [ 
                     phrase('hour', 'hours', 60*60),
                     phrase('minute', 'minutes', 60), 
                 ] | select('!=','') | list %}
          {{ values[:-1] | join(', ') ~ ' ' ~ word_for_and ~ ' ' ~ values[-1] if values | length > 1 else values | first }}


But I just answered the question of “hours & minutes”. Not “days, hours & minutes”.


Just trying to keep it simple until the requirements change.

Well, yeah that’s what the template I posted does. Just hours and minutes. But the hours aren’t capped at 24.

true, again.

the difference is in the simplicity.

yours is way more complicated. especially if there is no need for more than 24 hours.

Well there were no need for dates beyond 1999 so limiting to 24 hours should be fine :slight_smile:

1 Like

That still outputs 1 hour ahead of the actual time (it’s now 7 hours ago and your code outputs 8 hours)

This one works perfectly, thanks!

I know you said that you are using petro’s solution here is another template in my format that (I hope…) should be correct:

{% set time_diff =  (as_timestamp(utcnow()) - as_timestamp(states.input_datetime.example.last_changed)) | timestamp_custom('%H:%M', false)  %}
{{ time_diff.split(':')[0]}} Hours {{ time_diff.split(':')[1] }} Minutes

If you don’t mind could you test it for me to see if you get the correct results, please?

if it does work, TBH, I’m really not sure what’s going on with the first two attempts as to why they didn’t work. And I can’t explain what the reason is for why adding “false” to the custom timestamp formatting fixes the problem.

From my understanding and the testing I did in the template editor I am getting some strange results so I can’t explain it at all.

These shouldn’t matter. you can use as_timestamp(now()) or as_timestamp(utcnow()) and they both should return the same value. datetime objects have timezones associated with them and as_timestamp converts it into an integer that is based on UTC.

The issues lie in timestamp_custom('%H:%M', false). This assumes the input is a timestamp. When you subtract 2 timestamps, they are no longer timestamps. It’s now an int but it just so happens to work with timestamp_custom. But the problem with timestamp_custom is that it assumes Local so without the false it offsets the delta it by the timezone because timestamp_custom isn’t meant for time differences. It’s meant for moments in time, i.e. a timestamp int.


It wasn’t offsetting the time by just the timezone difference.

it was 19 hours off for me in my tests which I assume is because my TZ is +5. So, 24 - 5 = 19.

So it was doing some strange 24 hour time shift then offset the timezone.

It just surprised me since I’ve just never run into that before.

Take a look at the full date instead of just the hour and minute and you’ll see what’s happening.