Template for Christmas Season

I am not sure how it is in other areas of the world, but here in Germany the Christmas season officially starts with the “Adventszeit”. For Sundays prior to Christmas Eve we have the first Advent, where we light up the first candle on the “Adventskranz” and every Sunday one further candle is lit until on the forth Advent all four candles are burning.

Why am I telling all this? Currently I am using the following condition for my Christmas lighting automation:

  - condition: template #Only between December 1 and January 6.
    value_template: >
      {% set n = now() %}
      {{ n.month == 12 or ( n.month == 1 and ( 1 <= n.day <= 6 )) }}

Due to this the automation runs between the first of December and “Heilige Drei Könige”/Twelfth Day.
This year the first Advent was the 28th of November. Is there a way to create a template that is true for the time between the first Advent and Twelfth Day?

This template should do it:

{% set adventszeit = now().replace(day=24, month=12) - timedelta(days = 21 + now().replace(day=24, month=12).isoweekday() ) %}
{% set twelfth_day = now().replace(day=25, month=12) + timedelta(days = 12) %}
{{ adventszeit <= now() <= twelfth_day }}

You can check the dates in the Developer tools Template editor with this:

{% set adventszeit = now().replace(day=24, month=12) - timedelta(days = 21 + now().replace(day=24, month=12).isoweekday() ) %}
{% set twelfth_day = now().replace(day=25, month=12) + timedelta(days = 12) %}
Adventszeit is {{ adventszeit }}
Heilige Drei Könige is {{ twelfth_day }}
2 Likes

I believe the calculation for the First Advent is a bit more complicated. I ran the suggested calculation for several years and it doesn’t match what the TimeandDate site reports.

This:

{% for i in range(2016, 2027) %}
 {%- set adventszeit = now().replace(year=i, day=24, month=12) - timedelta(days = 21 + now().replace(year=i, day=24, month=12).isoweekday() ) -%}
 {{ adventszeit.date()}}
{% endfor %}

produces this:

2016-11-27
2017-11-26
2018-12-02
2019-12-01
2020-11-29
2021-11-28
2022-11-27
2023-11-26
2024-12-01
2025-11-30
2026-11-29

Compare that to this:

Year	Weekday	
2016	Sun	Nov 27	
2017	Sun	Dec 3	
2018	Sun	Dec 2	
2019	Sun	Dec 1	
2020	Sun	Nov 29	
2021	Sun	Nov 28	
2022	Sun	Nov 27	
2023	Sun	Dec 3	
2024	Sun	Dec 1	
2025	Sun	Nov 30	
2026	Sun	Nov 29

The date for years 2017 and 2023 differs from the online reference.

From Wikipedia:

It is possible to compute the date of Advent Sunday by adding three days to the date of the last Thursday of November; it can also be computed as the Sunday before the first Thursday of December.

I found an example in C# that adjusts its calculation for First Advent depending on whether Christmas is on a Sunday or not.

1 Like

Thank you both very much. @123 you are correct, it is not exactly as @tom_I has proposed.
There is one edge case, which is when christmas eve falls on a Sunday. Then the fourth Advend is on that exact day and not one week in advance.
I have split up the proposed template to understand its components and started to play around with it.
I guess if you run the calculations based on christmas day, it is correct:

{% for i in range(2016, 2027) %}
 {%- set adventszeit = now().replace(year=i, day=25, month=12) - timedelta(days = 21 + now().replace(year=i, day=25, month=12).isoweekday() ) -%}
 {{ adventszeit.date()}}
{% endfor %}

gives me the following values:

2016-11-27
2017-12-03
2018-12-02
2019-12-01
2020-11-29
2021-11-28
2022-11-27
2023-12-03
2024-12-01
2025-11-30
2026-11-29

I have simply replaced the day=24 with day=25 in both occasions.

The suggested template condition

  - condition: template #Only between Erster Advent and Heilige Drei Könige.
    value_template: >
      {% set first_advent = now().replace(day=25, month=12) - timedelta(days = 21 + now().replace(day=25, month=12).isoweekday() ) %}
      {% set twelfth_day = now().replace(day=25, month=12) + timedelta(days = 12) %}
      {{ first_advent <= now() <= twelfth_day }}

Did work correctly between the first advent and new years eve.
However in the new year the template is evaluating to false, as it is now considering the first advent of the new year (i.e. 2022). Any way to keep the relationship to the previous christmas until twelfth day has past?

{% set first_advent = now().replace(day=25, month=12) - timedelta(days = 21 + now().replace(day=25, month=12).isoweekday() ) %}
{{ first_advent <= now() <= now().replace(day=31, month=12) or now() <= now().replace(day=6, month=1) }}

Okay, that is quite simple, as it falls always on the same calendar day. Thanks for the support.

The start of Advent varies from year to year (see table above). So the twelfth day after the start of Advent isn’t January 6th every year (for a given year, it must be computed using the previous year’s start of Advent).

Then why did you originally calculate it as the twelfth day after the start of Advent?

Never mind; ignore my comments; I misunderstood the concept.

Twelfth Day/Epiphany/Three Kings Day is always Jan 6th… the same as @T1ppes template returns, because its 12 days after Christmas which is always Dec 25th.

 {% set twelfth_day= now().replace(day=25, month=12) + timedelta(days = 12) %}

It’s the beginning of Advent that changes, not the end.

1 Like

I see, not twelve days after the start of Advent but a religious day named Twelfth Day representing 12 days after December 25th. :man_facepalming:

1 Like

Just want to put this out here, in case it will help someone who stumbles upon this post. :slightly_smiling_face:

I ran some test scenarios and turns out, that for me, it was returning false for the first of advent and started to return true only the day after. Referring to the following:

In a Home Assistant template, comparisons between timestamps should generally take sub-second precision into account. However, there can be subtle differences in sub-second precision that may not be visible when printing the timestamps as strings. Home Assistant may handle sub-second precision differently when performing comparisons.

I ended up creating the below template (changed for Swedish traditions), altered to only take dates into consideration to avoid the above mentioned potential issue:

{% set first_advent = (now().replace(month=12, day=25) - timedelta(days = 21 + now().replace(month=12, day=25).isoweekday())).strftime('%Y-%m-%d') %}
{% set current_date = now().strftime('%Y-%m-%d') %}

{{ (current_date >= first_advent) and (current_date <= (now().replace(month=12, day=31)).strftime('%Y-%m-%d')) or (current_date <= (now().replace(month=1, day=12)).strftime('%Y-%m-%d')) }}

I also changed the conditional logic formatting, simply because I think that for clarity and readability, it’s better to use parentheses to explicitly group the conditions, especially when combining multiple conditions with different operators. This is just because thats a personal preference for me, and has nothing to do with that the other approaches are wrong.

This worked for me, and even though this perhaps can be further optimized/beautified, or be accomplished with another more precise approach, this is sufficient for my needs since I only need to check within specific dates, not HH:mm:ss:etc.