Disclosure: This article may contain affiliate links. If you decide to make a purchase, I'll make a small commission at no extra cost to you.
Over time I have created a large library of date and time manipulation code which are used in my automations and scripts. I plan to update this post with the snippets as I add to my library.
Date
Standard Examples
1
2
3
4
5
6
7
8
9
10
{% set date = as_timestamp(now())|timestamp_custom("%A %B %-d, %Y") %}
{% set datetime = as_timestamp(now()) | timestamp_custom("%I:%M:%S %p %b/%d/%Y", true) %}
{% set now_string = now().strftime("%Y-%m-%d") %}
{% set month_name = now().strftime("%B") %}
{% set day_name = now().strftime("%A")|lower %}
{% set this_month = now().month %}
{% set this_day = now().day %}
{% set this_year = now().year %}
timedelta()
1
2
3
4
5
# Calculate fifteen days ago.
{{ ( now() - timedelta(days=15) ).date() }}
# Calculate one week from today.
{{ ( now() + timedelta(weeks=1) ).date() }}
dayofweek_number(dayofweek)
ex. Get the number which represents Thursday. {{ dayofweek_number("Thursday") }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{%- macro dayofweek_number(dayofweek) -%}
{%- if dayofweek == "Sunday" or dayofweek == "Sun" -%}
0
{%- elif dayofweek == "Monday" or dayofweek == "Mon" -%}
1
{%- elif dayofweek == "Tuesday" or dayofweek == "Tue" -%}
2
{%- elif dayofweek == "Wednesday" or dayofweek == "Wed" -%}
3
{%- elif dayofweek == "Thursday" or dayofweek == "Thu" -%}
4
{%- elif dayofweek == "Friday" or dayofweek == "Fri" -%}
5
{%- elif dayofweek == "Saturday" or dayofweek == "Sat" -%}
6
{%- endif -%}
{%- endmacro -%}
last_dayofmonth(month, year)
ex. Get the last day of February 2020. {{ last_dayofmonth(2, 2020) }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{%- macro last_dayofmonth(month, year) -%}
{%- set daysinmonths = [31,28,31,30,31,30,31,31,30,31,30,31] -%}
{%- set month = month|int -%}
{%- set year = year|int -%}
{# Simplified leap year calculation. See https://www.mathsisfun.com/leap-years.html #}
{%- set isleapyear = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) -%}
{%- set monthindex = month-1 -%}
{%- if month == 2 and isleapyear -%}
{{ daysinmonths[monthindex]+1 }}
{%- else -%}
{{ daysinmonths[monthindex] }}
{%- endif -%}
{%- endmacro -%}
nth_dayofmonth(nth, dayofweek, month, year)
ex. Get the nth Monday of May.
1st: {{ nth_dayofmonth(1, "Monday", 5) }}
2nd: {{ nth_dayofmonth(2, "Monday", 5, 2020) }}
Last: {{ nth_dayofmonth("last", "Monday", 5) }}
Reference: bennadel.com
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{%- macro nth_dayofmonth(nth, dayofweek, month, year=now().year) -%}
{%- set dayofweek = dayofweek_number(dayofweek)|int -%}
{%- set firstdateofmonth = strptime(year ~"-"~ month ~"-1", "%Y-%m-%d") -%}
{%- set firstdayofmonth = dayofweek_number(firstdateofmonth.strftime("%A"))|int -%}
{# Determine the first occurrence of the day. #}
{%- if firstdayofmonth == 1 -%}
{%- set firstoccurrence = dayofweek -%}
{%- elif firstdayofmonth < dayofweek -%}
{%- set firstoccurrence = (dayofweek - dayofweek_number(firstdayofmonth)) -%}
{%- else -%}
{%- set firstoccurrence = (7 - firstdayofmonth + dayofweek) + 1 -%}
{%- endif -%}
{%- if nth is number -%}
{# Determine the nth occurrence of the dayofweek. #}
{%- set nthoccurrence = firstoccurrence + 7 * (nth-1) -%}
{%- else -%}
{#
Determine the LAST occurrence of the dayofweek.
Reference: https://cflib.org/udf/GetLastOccOfDayInMonth
#}
{%- set lastdayofmonth = last_dayofmonth(month, year)|int -%}
{%- set lastdayname = strptime(year ~"-"~ month ~"-"~ lastdayofmonth, "%Y-%m-%d").strftime("%A") -%}
{%- set lastdaynumber = dayofweek_number(lastdayname)|int -%}
{%- set daydifference = lastdaynumber - dayofweek -%}
{# Add a week if the result is negative. #}
{%- if daydifference < 0 -%}
{%- set daydifference = daydifference + 7 -%}
{%- endif -%}
{%- set nthoccurrence = lastdayofmonth - daydifference -%}
{%- endif -%}
{# Return the day with the month and year so it can be useful. #}
{{ strptime(month ~"/"~ nthoccurrence ~"/"~ year, "%m/%d/%Y") }}
{%- endmacro -%}
Time
Standard Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{# Current time using templates instead of requiring sensor.time. #}
{% set current_time = "%02d:%02d:%02d"|format(now().hour, now().minute, now().second) %}
{# Convert datetime to a timestamp. #}
{% set current_time = as_timestamp(now())|timestamp_custom("%I:%M %p") %}
{% set unix_timestamp = as_timestamp(now())|int %}
{# 24 hour version #}
{% set hour = now().hour %}
{# 12 hour version #}
{% set hour = now().strftime("%I")|int %}
{% set hour = iif(now().hour>12, now().hour-12, now().hour) %}
{% set minutes = now().minute %}
{% set seconds = now().second %}
{% set ampm = now().strftime("%p") %}
Between hours
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Standard way
{% if 6 <= now().hour and now().hour < 12 %}
0.25
{% elif 12 <= now().hour and now().hour < 17 %}
0.40
{% else %}
0.20
{% endif %}
# Shorter way
{% if 6 <= now().hour < 12 %}
0.25
{% elif 12 <= now().hour < 17 %}
0.40
{% else %}
0.20
{% endif %}
Add or subtract time
1
2
3
4
5
# 15 minutes ago.
{{ as_timestamp(now()) - timedelta(minutes=15) }}
# 12 hours from now.
{{ as_timestamp(now()) + timedelta(hours=12) }}
Difference between two times
1
2
3
4
# How long has it been since the last update?
{% set seconds_difference = (as_timestamp(now()) - as_timestamp(last_update)) %}
{% set minutes_difference = (seconds_difference) / 60 %}
{% set hours_difference = (seconds_difference) / 3600 %}
Add or subtract time
Pass a negative number to substract minutes instead of adding. add_minutes(start_time, -15)]
1
2
3
4
5
6
7
8
9
10
11
12
{% macro add_minutes(start_time, minutes_to_add) %}
{%- set now_datetime = now() %}
{%- set now_time = "%02d:%02d:%02d"|format(now_datetime.hour, now_datetime.minute, now_datetime.second) %}
{%- set new_datetime = now_datetime | replace(now_time, start_time) %}
{%- set new_datetime = as_datetime(new_datetime) + timedelta(minutes=minutes_to_add) %}
{%- set new_time = "%02d:%02d:%02d"|format(new_datetime.hour, new_datetime.minute, new_datetime.second) %}
{{ new_time }}
{% endmacro %}
{% set minutes_to_add = 5 %}
{% set boys = add_time(states("sensor.boys_room_next_alarm"), minutes_to_add) %}
{% set brian = add_time(states("sensor.wakeup_brian_time"), minutes_to_add) %}
Bonus: generate a list of dates
I use the template code below to generate a list of dates to add summer break to a school day sensor.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{%- macro last_dayofmonth(month, year) -%}
{%- set daysinmonths = [31,28,31,30,31,30,31,31,30,31,30,31] -%}
{%- set month = month|default(0)|int -%}
{%- set year = year|default(0)|int -%}
{# Simplified leap year calculation. See https://www.mathsisfun.com/leap-years.html #}
{%- set isleapyear = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) -%}
{%- set monthindex = month-1 -%}
{%- if month == 2 and isleapyear -%}
{{ daysinmonths[monthindex]+1 }}
{%- else -%}
{{ daysinmonths[monthindex] }}
{%- endif -%}
{%- endmacro -%}
{%- set year = now().year %}
{%- set months = [6,7,8] %}
{%- set days = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31] %}
{%- for month in months %}
{%- set lastday = last_dayofmonth(month, year)|int %}
{%- for day in days if day <= lastday %}
- "{{ year ~"-"~ "%02d"|format(month) ~"-"~ "%02d"|format(day) }}"
{%- endfor %}
{%- endfor %}
configuration.yaml snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
binary_sensor:
platform: workday
name: School day
country: US
province: CA
excludes: [sat, sun, holiday]
remove_holidays:
- Susan B. Anthony Day
add_holidays:
- "2022-04-04" # Spring recess
- "2022-04-05"
- "2022-04-06"
- "2022-04-07"
- "2022-04-08"
- "2022-04-11"
- "2022-04-12"
- "2022-04-13"
- "2022-04-14"
- "2022-04-15"