How do I format date within the Custom Button Card template?

Here is the code I am currently working with - the automation last triggered date shows up in the long hard to read ISO format - how do I get it to show in a more human readable format, and I just need the date and time separate. Not very familiar with date formatting syntax within the template for custom button card.

All help welcome - looking for the easiest way to solve this.

          - type: custom:button-card # All lights
            entity: group.all_lights
            name: Lights
            label: "[[[ return states['sensor.front_yard_motion_illuminance'].state + ' lux']]]" 
            state_display: |
              [[[
                var lights = states['group.all_lights'].state;
                if (lights == 'on') return 'Lights are on';
                else return 'All lights are off';
              ]]]
            custom_fields:
              s2: |
                [[[
                  var lux = states['sensor.front_yard_motion_illuminance'].state;
                  var newDate = states['automation.good_evening'].attributes.last_triggered;
                  if (lux > 250) return "Still bright outside";
                  else if (lux > 150) return 'Its getting dark';
                  else return  newDate;
                ]]]          
              s3: '&nbsp'            
            template: 
              - standard_btn_layout
              - standard_btn_states
              - standard_btn_states_on
              - animated_btn_states
              - light_btn
            icon: "mdi:home-lightbulb-outline"
            tap_action:
              action: more-info

I have removed the text in front of the newDate variable in the below screenshot.

image

The “template” is plain javascript.
Look for date formatting functions in JS.

Thank you - I had tried the following before posting and another method now. I’m familiar with the basics of js but not much else. So any more direction you can provide will be very helpful:

  • var prntDate = newDate.toLocaleDateString('en-US'); and
  • var prntDate = Intl.DateTimeFormat('en-US').format(newDate);

Both these errored out and today I saw on stack overflow that adding a “Z” to the end of the date string might work, but it is just giving me the current date and time, not converting my date variable

  • var prntDate = Date(newDate + "Z");

So I ended up creating a sensor for this with,

  • {{ as_timestamp(state_attr("automation.good_evening", "last_triggered")) | timestamp_custom('%b %-d'',''%I:%M %p') }}

and using that solved the problem, but I’m not sure that is the most elegant solution especially for something I only need for a lovelace dashboard. So, If you can please help tell me if there is a better way that you would choose, I would love to learn how to do this without creating a sensor for every new date I need.

Hi, can you post your templates please? I would like to create something similar and I don’t know where to start.

Sure, I am very much a noob at this as well - this forum, developer tools template tester and the jinja2 documentation has been the best help so far.

Hope this is what you wanted - just change the name of the automation to one of yours and restart and you should see this attribute now as a sensor. the code is that same as pasted above.

    auto_good_evening_last_triggered:
      friendly_name: Good Evening Last Triggered Time
      value_template: >
        {{ as_timestamp(state_attr("automation.good_evening", "last_triggered")) | timestamp_custom('%b %-d'',''%I:%M %p') }}
1 Like

Well, I meant the following templates, or am I wrong that these are templates that goes at the row config editor? I am a noob too

template: 
              - standard_btn_layout
              - standard_btn_states
              - standard_btn_states_on
              - animated_btn_states
              - light_btn

I modified portions of code I use that should work in your case. It’s not optimized but it’ll get the job done. It outputs relative time, the most relevant unit w/ units. i.e. 6 hours or 5 minutes, etc.

        var date = new Date(states['automation.good_evening'].attributes.last_triggered);
        let now = new Date();
        var tdelta = Math.floor((now - date)/1000);
        // console.log(`${entity_id}: ${tdelta}`);
        function plural(descriptor, divisor){
          var ret = Math.floor(tdelta/divisor);
          return (ret == 1) ? [ret, descriptor] : [ret, `${descriptor}s`];
        }
        var values;
        if (tdelta < 60)
          values = plural('second', 1);
        else if (tdelta < 60 * 60)
          values = plural('minute', 60);
        else if (tdelta < 60 * 60 * 24)
          values = plural('hour', 60 * 60);
        else if (tdelta < 7 * 60 * 60 * 24)
          values = plural('day', 60 * 60 * 24);
        else
          values = plural('week', 7 * 60 * 60 * 24);
        return values.join(' ');

If you’re trying to get “Nov 20, 10:00 AM”, then this will work:

var t = new Date(states['automation.good_evening'].attributes.last_triggered);
var options = {day:'numeric', month:'short', hour:'2-digit', minute:'2-digit'}
return t.toLocaleDateString("en-US", options);
8 Likes

Thank you @petro. Both these options worked beautifully. I was after the second option but the x hours/min/seconds ago might make more sense. Thanks for sharing this.

I have used your code and responses to other posts in this forum to teach myself quite a bit of what I am doing with HA, and this response had the same result, learning. So I owe you a big thank you!

1 Like

Those are not mine - I got them from here and edited it quite a bit to look like this.

1 Like

One more question please - I am using the following template to count all the light switches that are on. Which means starting with all switches an then exclude all those are not controlling lights (e.g. sprinklers, pi-hole, shades, browser-mod etc)

It works but I am sure there is way to simplify this code here, tried ways to include all the value pairs as a list or dictionary, and then compare that but did not work. Is there a simpler way to achieve this result?

        {% set count = namespace(value=0) %}
        {%- for item in states['switch'] if item.state == 'on' and (item.attributes.friendly_name.split(' ',1)[0] != 'B-Hyve' and item.attributes.device_id != '60a2ad344f0cc5e78a2e8fe0' and item.attributes.friendly_name.split(' ',1)[0] != 'Oommen' and item.attributes.friendly_name != 'Pi-Hole' and item.attributes.friendly_name.split(' ',1)[0] != 'NZBGet' and item.attributes.friendly_name.split('-',1)[0] != 'Bedroom Shade ' and item.attributes.friendly_name.split('-',1)[0] != 'Bathroom Shade' and item.attributes.friendly_name.split(' ',1)[1] != 'Shades') -%}
        {# (item.attributes.friendly_name.split('-',1)[0]) #}
        {% set count.value = count.value + 1 %}
        {%- endfor %}
        {{ count.value }}
{{ expand(states.switch) | selectattr('state','eq','on') | map(attribute='attributes.friendly_name') | reject('search', 'B-Hyve') | reject('search', 'Shade') | list | count }}

however that doesn’t filter the device_id because you can’t use selectors for that. You’d have to continue to use your current template for that.

Thank you. I decided to create a group of all the light switches and go with the below:

{{ expand(states.group.light_switches) | selectattr('state','eq','on') | list | count}}

The group would be another thing to maintain - but adding new light switches to the group should be easier than editing the script based on attributes was the thought.

Change it to this to make it more safe on startup:

{{ expand('group.light_switches') | selectattr('state','eq','on') | list | count }}
1 Like

Will do - is that based on the same logic as the below note from the HA docs.

Avoid using states.sensor.temperature.state , instead use states('sensor.temperature') . It is strongly advised to use the states() , is_state() , state_attr() and is_state_attr() as much as possible, to avoid errors and error message when the entity isn’t ready yet (e.g., during Home Assistant startup).

1 Like

Yes, it’s exactly that

1 Like
    sensor_4: >-
      [[[ return `${states[ 'sensor.' + variables.var_sensor_name +
      '_last_seen' ].state}` ]]]

How can I specify the normal hours-minutes-seconds format in the template?

you have to perform the math yourself. I provided an example in this thread.

I really don’t understand this

              {% if as_timestamp(sensor.last_changed) == as_timestamp(sensors | 
                 map(attribute='last_changed') | max) %}
                {{ sensor.name }}
                {{ '{:d} day {:02d}:{:02d}:{:02d}'.format (s // 86400, s % 86400 // 3600, s % 3600 // 60, s % 60) 
              }}

I use these templates

but I don’t know how to write it in this card

that’s jinja, the card uses JS.

I understand. I’ll ask again somewhere else