How to do timezone-agnostic comparisons with selectattr?

I’m using the selectattr() filter to test a known time to a list of timestamp attributes.

My energy provider gives me a list of dynamic hourly prices. A restful sensor returns this list to Home Assistant with the list as a json attribute.

[{'total': 0.3354, 'startsAt': '2024-09-13T00:00:00.000+02:00'},
{'total': 0.3254, 'startsAt': '2024-09-13T01:00:00.000+02:00'},
{'total': 0.3204, 'startsAt': '2024-09-13T02:00:00.000+02:00'},
{'total': 0.3197, 'startsAt': '2024-09-13T03:00:00.000+02:00'},
{'total': 0.3172, 'startsAt': '2024-09-13T04:00:00.000+02:00'},
...

I wanted to use selectattr() to filter for a specific timestamp. Due to reasons it’s possible to get the desired value in a different timezone.

selectattr('startsAt', 'eq', targetvalue)

does not work if targetvalue is 2024-09-13T00:00:00+00:00 as Jinja2 appears to do a simple string comparison here. Apparently Jinja2 doesn’t do datetime comparions?

Is there a proper way to do date comparisons with selectattr() or must I convert all to unix timestamps?

It is doing string comparisons because your values from the json object are datetime strings, not datetime objects. If they were datetime objects you could do full datetime comparisons. But it seems like it would be easier (and more efficient) to fix targetvalue than to extract the strings, convert them to datetime objects, and reassemble the dictionary…

1 Like

json doesnt support date/time objects. yoy need to find a way to postprocess these otems and tuan them into datetime objects. check jinja templating docs for that.

1 Like

The code below will convert all the timestamp strings into timestamp objects, then zip it back up into a list of tuples with the value from total, and then you can use selectattr() to do real datetime comparisons (so timezones are taken into account). Play around with it in the template editor in developer tools.

{% set my_list = [
  {'total': 0.3354, 'startsAt': '2024-09-13T00:00:00.000+02:00'},
  {'total': 0.3254, 'startsAt': '2024-09-13T01:00:00.000+02:00'},
  {'total': 0.3204, 'startsAt': '2024-09-13T02:00:00.000+02:00'},
  {'total': 0.3197, 'startsAt': '2024-09-13T03:00:00.000+02:00'},
  {'total': 0.3172, 'startsAt': '2024-09-13T04:00:00.000+02:00'}
] %}
{% set comparetime = '2024-09-13T01:00:00.000+00:00' | as_datetime %}
{% set start = my_list | map(attribute='startsAt') | map('as_datetime') | list %}
{% set total = my_list | map(attribute='total') | list %}
{{ zip(total, start) | selectattr(1, '==', comparetime) | map(attribute=0) | first }}
3 Likes

Awesome. Thanks to everybody, this is very helpful for me to understand what’s going on there.

I will want to do some more calculations using the startsAt values in the json object, so it would actually be better if I did just that - convert the string values of startsAt to datetime objects after the rest query complected, so that the JSON attribute contains the proper datetime object type.

So is there a way to postprocess the JSON of a restful sensor in a way that the json attribute’s datetime strings are converted to proper datetime objects?

(I found other people asking for this, but didn’t find a solution with a code example.)

Thanks again!

The attributes in the RESTful sensor don’t support templates, so you have two options:

  1. Create a template sensor (in YAML) that post-processes the attribute data from the RESTful sensor into the template sensor’s attributes. Keep in mind that all states are strings, but attributes can be other types, so you don’t want to process the result into the state of the template sensor.
  2. Instead of a RESTful sensor, use a custom integration like multiscrape which supports templates in attributes.