The EPIC Time Conversion and Manipulation Thread!

It looks like:

Timestamp: 2022-01-07 09:43:00+00:00

This integration shows the timestamp in exactly the same format regardless of whether I use
{{ package.timestamp }} or
{{ package.timestamp | timestamp_custom("%d-%m-%y") }}
to display it. It’s crazy!

Try:

{{ package.timestamp | as_datetime | timestamp_custom("%d-%m-%y") }}

When it renders the same format, that means it’s failing to convert it. Check your logs and it will tell you that.

If you want it local time and not utc…

{{ package.timestamp | as_datetime | as_local | timestamp_custom("%d-%m-%y") }}
1 Like

Thanks @parautenbach and @petro . Unfortunately neither of these syntaxes worked - the entire card output disappears as it can’t be rendered correctly.

The log says:

  • Template warning: ‘timestamp_custom’ got invalid input ‘2022-01-07 09:43:00+00:00’ when rendering template '{% for package in states.sensor.seventeentrack_packages_expired.attributes.packages %} - Timestamp: {{ package.timestamp | timestamp_custom("%d-%m-%y") }}. {% endfor %} ’ but no default was specified. Currently ‘timestamp_custom’ will return ‘2022-01-07 09:43:00+00:00’, however this template will fail to render in Home Assistant core 2022.1

The last sentence is interesting: timestamp-custom will return a value but it’s not the value that was specified.
What should I try next?

{{ package.timestamp | as_datetime | as_local | as_timestamp | timestamp_custom("%d-%m-%y") }}
1 Like

Still not successfully working. Stepping through this:
package.timestamp returns 2022-01-07 09:43:00+00:00
piping only to as_timestamp returns 1641548580.0
piping only to as_datetime fails to return a value
piping to as_timestamp | as_datetime does return 2022-01-07 09:43:00+00:00
piping to as_timestamp | as_datetime | as_local does return 2022-01-07 22:43:00+13:00 ← progress!
piping to as_timestamp | as_datetime | as_local | timestamp_custom("%a") however only gives me 2022-01-07 22:43:00+13:00.

This worked:
piping to package.timestamp | as_timestamp | timestamp_custom("%A %D %z %Z") gives me Friday 01/07/22 +1300 NZDT which is correct, and in a format I can work with.

So, for this timestamp, it’s pretty resistant to being worked with as a datetime, but I can apply a custom format if I leave it as a timestamp.
Thanks for helping me work this out!

This works:

but you didn’t try it, you skipped over it and reversed the as_timestamp to the front.

timestamp_custom requires a timestamp to precede it. Admittedly, I forgot as_timestamp can convert a string to an timestamp. Regardless, both of these will work

{{ package.timestamp | as_datetime | as_local | as_timestamp | timestamp_custom("%d-%m-%y") }}
{{ package.timestamp | as_timestamp | timestamp_custom("%d-%m-%y") }}

this will also work

{{ (package.timestamp | as_datetime | as_local).strptime("%d-%m-%y") }}
1 Like

Sorry, but this one definitely did not work. I tried it early on as it was already suggested earlier in the thread.

Unfortunately this one didn’t work for me either.

There is nothing special about my 17track card here, so I am unsure why these work for you and not me. Regardless, using as_timestamp | timestamp_custom(... worked well so I’m glad to have this working now. Thanks for the help!

Are you trying these in the template editor? Are you using the latest version of HA?

I’m trying them in my live setup so I am reporting real-world status of “works/doesn’t work”. And yes, I am using the latest version of HA, always! Thanks.

Hi,
I am not very familiar with Jinja templates, mostly get syntax from all awesome guys posting in this community. however I couldn’t find what I am searching for.

I need to show the last changed time as follows:

  1. If less than 24hrs to show ‘15 hours ago’ or ‘Today at 16:25’
  2. If more between 24-48hrs to show ‘Yesterday at 16:25’
  3. If more than 48hrs to show ‘Tuesday at 16:25’

I really appreciate any advice
Thanks in advance
RS

Rami, this may be taking your brief too literally, but try the following:

{% set last_changed = states.sensor.XXXX.last_changed %}
{%- set delta = (now() - last_changed | as_local).total_seconds() / 3600 %}
{%- set weekday = last_changed.strftime("%A") %}
{%- set time = last_changed.strftime("%H:%M") %}
{%- if delta < 24 %} {{ [ "Today at "~time, delta|round(0)~" hours ago" ] | random }}
{%- elif 24 < delta < 48 %} Yesterday at {{ time }}
{%- else %} {{ weekday~" at "~time}} {%- endif %}

Thank you very much Drew, This is perfect… I tried it. below my observation:

  • Current time 18:52 (GMT+3)
  • At first it displays ‘Today at 14:52’ then about 30 seconds later it displays ‘1 hours ago’

I think it has something to do with when the code/entity refreshes!
I will give it more time and see how it goes.

Much appreciate it though on the logic/code a lot to be learnt from for other stuff as well :smiley:

That’s what I meant by “taking your brief too literally”… :grinning_face_with_smiling_eyes:

You wrote:

The following clause causes it to randomly shuffle between the two formats every time the template refreshes:

{{ [ "Today at "~time, delta|round(0)~" hours ago" ] | random }}

You can switch it out for either {{ "Today at "~time }} or {{ delta|round(0)~" hours ago" }}

this should get you what you want.
You will need to put your data in for the ‘time’ variable.

{% set time = states('input_datetime.both_date_and_time') %}
{% if as_timestamp(time) | timestamp_custom('%Y-%m-%d') == as_timestamp(now()) | timestamp_custom('%Y-%m-%d') %}
  Today at {{ as_timestamp(time) | timestamp_custom('%H:%M') }} ({{ ((as_timestamp(now()) - as_timestamp(time)) / 3600 ) | int}} hours ago)
{% elif as_timestamp(time) | timestamp_custom('%Y-%m-%d') == (as_timestamp(now().replace(hour=0, minute=0, second=0)) - 3600) | timestamp_custom('%Y-%m-%d') %}
  Yesterday at {{ as_timestamp(time) | timestamp_custom('%H:%M') }}
{% elif as_timestamp(time) < as_timestamp(now().replace(hour=0, minute=0, second=0)) - (3600 * 1) and as_timestamp(now()) - 84600 * 7 < as_timestamp(time) %}
  {{ as_timestamp(time) | timestamp_custom('%A at %H:%M') }}
{% else %}
  More than a week ago
{% endif %}

there may be a more elegant way to do it but this works in my testing.

see what you think.

2 Likes

LOL, indeed that was ‘literally’ but the ‘Today…’ format displays the GMT time not the local time

Ok, I understand now… Move the as_local filter so that it is applied to the variable last_changed the first two lines should be:

{% set last_changed = states.sensor.XXXX.last_changed | as_local %}
{%- set delta = (now() - last_changed).total_seconds() / 3600 %}
1 Like

Thank you @finity & @Didgeridrew for your help… Both solutions work flawlessly…

FYI, you guys can utilize today_at to make the template really easy to read without any fancy math.

{% set last_changed = states.binary_sensor.main_door.last_changed %}
{% if last_changed < today_at() - timedelta(days=1) %}
  {{ last_changed.strftime('%A at %H:%M') }}
{% elif last_changed < today_at() %}
  {{ last_changed.strftime('Yesterday at %H:%M') }}
{% else %}
  {{ last_changed.strftime('Today at %H:%M') }}
{% endif %}
2 Likes

Wow… and I just finished modifying @finity 's to be:

{% set time = states('input_datetime.test_datetime_3') %}
{% set hrs = ((as_timestamp(now()) - as_timestamp(time)) / 3600 ) | int %}
{% set mins = ((as_timestamp(now()) - as_timestamp(time))  ) | timestamp_custom('%M') |int %}
{% if as_timestamp(time) | timestamp_custom('%Y-%m-%d') == 
     as_timestamp(now()) | timestamp_custom('%Y-%m-%d') %}
  Today at {{ as_timestamp(time) | timestamp_custom('%H:%M') }} 

    {% if hrs == 0 %}
        ({{ mins | int}} minute(s) ago)
    {% elif hrs == 1 %}
        ({{ hrs | int}} hour ago)
    {% else %}
        ({{ hrs | int}} hours ago)
    {% endif %}


{% elif as_timestamp(time) | timestamp_custom('%Y-%m-%d') == 
       (as_timestamp(now().replace(hour=0, minute=0, second=0)) - 3600) 
         | timestamp_custom('%Y-%m-%d') %}
  Yesterday at {{ as_timestamp(time) | timestamp_custom('%H:%M') }}

{% elif as_timestamp(time) < as_timestamp(now().replace(hour=0, minute=0, second=0)) - (3600 * 1)
    and as_timestamp(now()) - 84600 * 7 < as_timestamp(time) %}
  {{ as_timestamp(time) | timestamp_custom('%A at %H:%M') }}
{% else %}
  More than a week ago
{% endif %}

adding the following lines:

{% set hrs = ((as_timestamp(now()) - as_timestamp(time)) / 3600 ) | int %}
{% set mins = ((as_timestamp(now()) - as_timestamp(time))  ) | timestamp_custom('%M') |int %}

    {% if hrs == 0 %}
        ({{ mins | int}} minute(s) ago)
    {% elif hrs == 1 %}
        ({{ hrs | int}} hour ago)
    {% else %}
        ({{ hrs | int}} hours ago)
    {% endif %}

I will try your code @petro right away :slight_smile: