Currently, if you want to do some simple date math, like add or subtract 7 days from today’s date, you have to go through arithmetic gymnastics involving conversions to and from timestamps. It would be far simpler if python’s timedelta were available for templating purposes.
Subtracting 7 days from today’s date would be just this:
{% set the_past = now() - timedelta(days=7) %}
The date and time in 12 hours:
{% set the_future = now() + timedelta(hours=12) %}
and if we add timedeltas, make the custom filters work off them. Might as well extend relative time to work in the future as well. There’s about 90 kajillion things that need to be added to make time calculations better in templates.
Yes, but I mean as long as you can do math in the timedelta then. There is no harm.
I mean instead of days=7 just do 7*86400.
But two times a year that will fail.
…
Ok I withdraw my previous comment.
Yes full timedelta is better.
Don’t know how much extra that is in implementation, but since the function exists in python I assume it’s minimal.
Maybe I’m missing it here but I’m having a very hard time with the Home Assistant timedelta sensor. I’m trying to calculate a “bandwidth per day” value by using the time left in my billing cycle and the remainder of my data cap but for some reason the Home Assistant timedelta sensor I created doesn’t contain the same attributes as the timedelta python object.
I was referencing the timedelta python page and it shows that timedelta objects have attributes for days, seconds and microseconds so I implemented this:
sparklight_usage_per_day_left:
friendly_name: Sparklight Usage Per Day Left
value_template: >
{{ (states('sensor.sparklight_usage_remaining') / (state_attr('sensor.sparklight_billing_days_left', 'days') + state_attr('sensor.sparklight_billing_days_left', 'seconds')/86400)) | round(2) }}
It doesn’t work, and through the template page I found that {{ states('sensor.sparklight_billing_days_left') }} results in a string like: 14 days, 13:54:00 and I cannot get attributes for days, seconds, nor microseconds from the sensor. I tried piping to float and int and that results in zero. Is there an easy way to do what I’m trying to do?
I guess I was – or at least with attributes that represented the constituents of the timedelta. I can think of two ways to do this but both seem very non-pythonic:
I can duplicate the code for calculating the timedelta in the template sensor where I need it because then the python timedelta object contains the days/seconds attributes (billing_time_left.days, and billing_time_left.seconds). I did this in the template tool first to prove out the functionality but I was hoping to easily re-use the sensor values in the same way.
{%- set today = now().replace(tzinfo=None, microsecond=0) -%}
{%- set billing_day = strptime('{}-{}-21'.format(today.year, today.month),'%Y-%m-%d') -%}
{%- if as_timestamp(billing_day) - as_timestamp(today) <= 0 -%}
{%- if today.month == 12 -%}
{%- set billing_day = strptime('{}-01-21'.format(today.year+1),'%Y-%m-%d') -%}
{%- else -%}
{%- set billing_day = strptime('{}-{}-21'.format(today.year, today.month+1),'%Y-%m-%d') -%}
{%- endif -%}
{%- endif %}
{%- set billing_time_left = billing_day - today -%}
If today is: {{ today }}
Billing day is: {{ billing_day }}
Bandwidth left: {{ (350 - (states('sensor.wan_monthly_data_in')|float + states('sensor.wan_monthly_data_out')|float)/1e9)|round(4) }}
Time left: {{ billing_time_left }}
Bandwidth left per day: {{ (((350 - (states('sensor.wan_monthly_data_in')|float + states('sensor.wan_monthly_data_out')|float)/1e9)|round(4))/(billing_time_left.days + billing_time_left.seconds/86400)) | round(2) }}GB/day
This code works all together, and produces:
If today is: 2020-12-06 10:56:44
Billing day is: 2020-12-21 00:00:00
Bandwidth left: 291.2344
Time left: 14 days, 13:03:16
Bandwidth left per day: 20.02GB/day
Alternatively, I can decompose the string into separate days and timestamp values and manually calculate the floating point number of days remaining.
It just feels dirty to copy the entire block of code into a second sensor just to recalculate the timedelta object so I can use it again for another purpose.
Looking for guidance on how best to handle this. Also, I know you guys are much more efficient at logic blocks than I am so if you have suggestions on ways to tighten it up, I’m all ears!