ashscott
(Ash)
November 25, 2022, 10:30pm
1
I have a date that is a string in the format 10/06/2023.
I need to have a sensor that shows the number of days to go until that date.
Where do I start with this?
I’m thinking that the string first needs to be converted into a date and then converted into number of days.
I’ll then need to compare that with today’s date.
I’d rather not have a finished solution, just some pointers as to where to start.
Dujith
(Charles Evers)
November 25, 2022, 10:45pm
2
I keep seeing questions about calculating days away from a calendar date. Here’s a “simple” template that will solve that problem for anyone.
{% set midnight = today_at() %}
{% set event = state_attr('calendar.xxx', 'start_time') | as_datetime | as_local %}
{% set delta = event - midnight %}
{% if delta.days == 0 %}
Today
{% elif delta.days == 1 %}
Tomorrow
{% elif delta.days == 2 %}
Day After Tomorrow
{% else %}
In {{ delta.days }} Days
{% endif %}
Explanation
This first line grabs …
This will explain the how. So you can also set a date helper for this or another entity.
2 Likes
123
(Taras)
November 26, 2022, 12:14am
3
Copy-paste the following template into the Template Editor and confirm it reports the desired result.
{{ (strptime('10/06/2023', '%m/%d/%Y', today_at()) | as_local - today_at()).days }}
Replace '10/06/2023'
with states('sensor.your_sensor')
or whatever is needed to get the date string.
2 Likes
ashscott
(Ash)
November 26, 2022, 8:05am
4
Thank you! That works brilliantly.
I’m using {{ states('sensor.my_date')[-11:] }}
to get the 10/06/23
and it returns the string correctly.
Substituting it into your template thus…
{{ (strptime(states('sensor.my_date')[-11:], '%m/%d/%Y', today_at()) | as_local - today_at()).days }}
… it just returns 0
as the result.
Am I expecting too much of it?
Does it need to be done in two steps?
The original string takes the form "196 hrs or 10/06/2024"
This is what I’m pasting into the Template Editor:
{{ states('sensor.my_date')[:3] }}
{{ states('sensor.my_date')[-11:] }}
{{ (strptime(states('sensor.my_date')[-11:], '%m/%d/%Y', today_at()) | as_local - today_at()).days }}
{{ (strptime('10/06/2023', '%m/%d/%Y', today_at()) | as_local - today_at()).days }}
And that returns this:
196
10/06/2024
0
314
Which highlights another issue.
When the 196 hrs changes to 99 hrs the {{ states('sensor.my_date')[:3] }}
it will return "99 ", as there are only two digits. Same problem when it reaches 9.
Is there a way to extract the number up to the first “space”?
123
(Taras)
November 26, 2022, 12:47pm
6
Change [-11:]
to [-10:]
because the date string is ten characters long.
[-11:]
will include a leading space which doesn’t match strptime’s pattern. As a consequence, strptime reports its default value which is today_at().
ashscott
(Ash)
November 26, 2022, 1:05pm
7
I looked at that, but changing it to -10 loses the 1, resulting in a date of 0/06/2024.
In principle though, should it work? If so then an erroneous character may well be the problem, as you suggest.
123
(Taras)
November 26, 2022, 1:08pm
8
That behavior implies there’s a trailing space character in the original string.
Try this:
states('sensor.my_date')[-11:] | trim
Revised example:
{{ (strptime(states('sensor.my_date')[-11:] | trim, '%m/%d/%Y', today_at()) | as_local - today_at()).days }}
1 Like
ashscott
(Ash)
November 26, 2022, 1:17pm
9
Excellent. Thank you.
So, ‘trim’ removes just trailing spaces?
Is there something similar to deal with the varying lengths, as per my 196 to 99 hours problem above?
I don’t think there are leading spaces there but just extracting up to the first space would solve the problem.
123
(Taras)
November 26, 2022, 1:36pm
10
trim
removes leading and trailing white space.
If the string always contains hrs or
you can use it as a delimiter in split()
. The result will be a list containing two items, 99
and 10/06/2024
, that can be referenced by list index.
Try this in the Template Editor:
{% set x = states('sensor.my_date').split(' hrs or ') %}
{{ x[0] }}
{{ x[1] | trim }}
1 Like
ashscott
(Ash)
November 26, 2022, 1:53pm
11
Thank you.
That works.
In English, for my understanding, it’s taking the string and removing everything on either side of what is in the split().
This then leaves a list, x, with each list item being referenced by [y].
You have taught me so much!
Thank you and have a great weekend.
1 Like
123
(Taras)
November 26, 2022, 1:58pm
12
You’re welcome!
Please consider marking my post above with the Solution tag. It will automatically place a check-mark next to the topic’s title signaling to other users that this topic has been resolved. This helps users find answers to similar questions.
For more information about the Solution tag, refer to guideline 21 in the FAQ .