Week number as condition

@Hellis81
Great - thank you very much, it was excatly what I was looking for.

Hi there, I am currently using your conditiom for even week and it working fine, unfortunately odd weeks not working. Can you give me sime advice what is wrong in my code please?

Even week

- id: '1603291066243'
  alias: 'Door sensor even week '
  description: 'Lichý týden '
  trigger:
  - platform: state
    entity_id: binary_sensor.openclose_3
    to: 'on'
  condition:
  - condition: template
    value_template: '{{ not now().strftime(''%W'') | int % 2 }}'
  - condition: time
    after: '11:45:00'
    before: '21:30:00'
    weekday:
    - mon
    - tue
    - wed
    - thu
    - fri
  action:
  - service: notify.notify
    data:
      message: Otevřené vstupní dveře
  mode: single

and ODD week configuration

- id: '1603301749528'
  alias: 'Door sensor  odd week  '
  description: 'Sudý týden '
  trigger:
  - platform: state
    entity_id: binary_sensor.openclose_3
    to: 'on'
  condition:
  - condition: template
    value_template: "{{ now().isocalendar()[1] % 2 }}"
  - condition: time
    after: '04:30:00'
    before: '20:30:00'
    weekday:
    - mon
    - tue
    - wed
    - thu
    - fri
  action:
  - service: notify.notify
    data:
      message: Otevřené vstupní dveře
  mode: single

Any help appreciated

The template is incorrect. Change it to this to check for ODD weeks:

  - condition: template
    value_template: "{{ now().isocalendar()[1] % 2 != 0 }}"

if the result of now().isocalendar()[1] is 0, it’s an EVEN week. If the result is not 0 then it’s an ODD week.

Thanks Taras, so i just put the same code, restart and nothing happened :cold_face:

There’s a weekday condition for Mon to Fri. Today is Sunday.

Yes i know, i made sunday as well, check it out:

- id: '1603301749528'
  alias: 'Door sensor  odd week  '
  description: 'Sudý týden '
  trigger:
  - platform: state
    entity_id: binary_sensor.openclose_3
    to: 'on'
  condition:
  - condition: template
    value_template: "{{ now().isocalendar()[1] % 2 != 0 }}"
  - condition: time
    after: '04:30:00'
    before: '20:30:00'
    weekday:
    - mon
    - tue
    - wed
    - thu
    - fri
    - sun
  action:
  - service: notify.notify
    data:
      message: Otevřené vstupní dveře
  mode: single

Here’s the thing, you ask for assistance but you don’t post the automation that you are actually using. This makes it very difficult for other people to help you because they can only work with what you post here. In the future, please post precisely what you are using when you report: “I just put the same code, restart and nothing happened”. The assumption is that you are using the automation you posted and not something different.

This checks for ODD weeks:

{{ now().isocalendar()[1] % 2 != 0 }}

If you paste it into the Template Editor it will report false which is correct because we are currently in week 44 which is an even week.

https://www.epochconverter.com/weeknumbers

Sure, you are right. I just turn over my odd / even weeks in automation and brain as well. Sorry for misunderstanding, now its working great, its clear for me now. Thank you again!

1 Like

There is a bug with checking whether an ISO week number is odd or even to get a biweekly pattern. The problem is that every 5 or 6 years there will be a year with 53 weeks causing two consecutive weeks that are odd numbered. This last happened in 2020 and will next happen in the year 2026. For something like controlling lights, you might not notice. However for things on a perpetual biweekly schedule like paydays and rotating shift schedules, your scripts will break every time you encounter ISO week 53.

The solution I have found is to create an ordinal week number (new week begins on Sunday) from the ordinal day number. In Jinja2 use the following…

{{((now().toordinal())/7)|int}}

Check for an even week with following expression.

{{((now().toordinal())/7)|int is divisibleby 2 }}

In the year 2023 this ordinal week number agrees with the ISO week number in oddness and evenness However after the last week of 2026 it won’t as that is when the next ISO 53 week year occurs.

It’s not a bug, it’s how the calendar works.
You could have a boolean that toggles every time the template {{now().isocalendar()[1] }} changes.

As hellis said, it’s not a bug, that’s how odd/even works. Some calendar years have 53 weeks. If you want alternating weeks forever, then you need to set a date (never change it) and base your by weekly calculation off that date.

{{ ((now() - '2000-01-01T00:00:00+0000' | as_datetime | as_local).days // 7) % 2 }}

But then you get leap years and when 7 leap years has passed you get out of sync. Although a long time in the future, it’s still possible

What? No, this is a simple calculation that just does by weekly odd/even forever. It’s not tied to the current week. This was simply to give eyager a never ending by-weekly flag.

You are right. I was not thinking straight

FWIW, I think I saw CentralCommand do the same thing (compute alternating weeks based on a reference date) in another post but employing the Unix Epoch for the reference date (concise conversion to a datetime object):

{{ ((now() - as_datetime(0)).days // 7) % 2 }}

yeah, but it’s missing as_local so the flag will switch at UTC instead of your local timezone. It also might complain about comparing non-tz aware to tz-aware. I always try to cover all bases so that I’m not guessing

EDIT: Seems that it doesn’t attach the TZ the way I expected. So even my template has this issue.

{{ ((now() - (as_datetime(0) - now().utcoffset()) | as_local).days // 7) % 2 }}

as_local isn’t really needed in this

{{ ((now() - as_datetime(0) - now().utcoffset()).days // 7) % 2 }}

I can confirm as_datetime(0) produces the Unix Epoch as a tz-aware datetime object.

I can’t comment on “flag will switch at UTC” because I’ve never thought about how/when timezone conversion is performed when subtracting two datetime objects where one isn’t UTC and the other is. I thought it would simply handle both as UTC to produce the timedelta object. In other words, effectively this:

{{ ((utcnow() - as_datetime(0)).days // 7) % 2 }}

My TZ is -5, so without adding 5 hours to the UTC, the week flag will flip 5 hours ahead of midnight my time.

In my above math, my timedelta is negative so subtracting it will add 5 hours to the timedelta

it’s possible I’m over thinking it atm,

OK, I now understand what you’re saying.

I’ll create something to report the template’s result at regular intervals prior to midnight and see when the reported value toggles.

I guess I should modify it to toggle on a daily basis (otherwise I’ll have to wait a long time for results). :slightly_smiling_face: