Days until payday (adjust if payday is on weekend) using local calendar

I have created a recurring event in my local calendar where I have added a payday event on the 25:th each month.
I would like to create a template sensor that tracks the days until the next payday. But I would also like to have it adjusted so that if the payday is on a saturday or sunday the payday will be on the previous friday.

Can anyone help me understand how to create this kind of template sensor ?

You could maybe consider using the calendar function built into HA to make a recurring event

sorry I might have explained it bad. I already have the recurring event in the built in calendar.

Sorry, it’s early for me. I guess i missed that part.

What I would suggest is to create a sensor that grabs the first next date from your calendar and stores that as a date + time.

Then check if it is a weekend day using the weekday() function. And I think it calculates from sunday being day 1. So if result is 1, to adjust that sensor to do take off 2 days and if its 7 to take off 1 day. That way you get the right reporting.

I am not at a computer right now, but if I manage to free up some time later today, I could provide something here (unless someone else beats me to it :smiley: )

This is do-able without referring to a Calendar event. Referring to a calendar event is possible, but would be more complicated than necessary.

template:
  - sensor:
      - name: Days Until Payday
        state: |
          {%- macro correct_day(day_25) %}
          {%- set wd = day_25.isoweekday() %}
          {%- set corrected = day_25 if wd < 6 else day_25 - timedelta(days= (wd-5)) %}
          {{- corrected }}
          {%- endmacro %}

          {% set today = today_at() %}
          {% set next_25 = (today + timedelta(days=(32-today.day))).replace(day=25) %}
          {% set this_c = (correct_day( today.replace(day=25))|as_datetime ).date() %}
          {% set next_c = (correct_day(next_25)|as_datetime).date() %}
          {{ (this_c - today.date()).days if this_c > today.date() else (next_c - today.date()).days}}

EDIT: Corrected issue with timedelta and days after payday

If you really want to use a calendar reference
trigger:
  - platform: time
    at: "00:01:00"
  - platform: event
    event_type: event_template_reloaded
action:
  - service: calendar.list_events
    data:
      duration:
        hours: 744
        minutes: 0
        seconds: 0
    target:
      entity_id: calendar.EXAMPLE
    response_variable: agenda
sensor:
  - name: Days Until Payday
    state: |
      {% set today = today_at() %}
      {% set uncorrected = ((agenda.events 
      | selectattr('summary', 'search', 'pay day', ignorecase=1) 
      | sort(attribute='start') | first)['start'] | as_datetime).date() %}
      {% set wd = uncorrected.isoweekday() %}
      {% set corrected = uncorrected if wd < 6 else uncorrected - timedelta(days= (wd-5)) %}
      {{ (corrected - today.date()).days }}
1 Like

Thanks for the help, I tried the first example but I am to unskilled to understand how the code works.
Is this part correct ?
{% set next_25 = (today + timedelta(days=(31-today.day))).replace(day=25).date() %}

As I said I don’t exactly understand the code but does 31-today.day always work ? I was thinking that a month also can have 30 or 28 days?

That actually should have been 32. The purpose of timedelta(days=(32-today.day)) is to add enough days to the current date to get to the next month, but not so many that is goes into the month after that. So we subtract the current day of the month from 32 than add the difference to the current day. Using 32 as the constant means it will always render as date between the 1st and 4th. After that the .replace(day=25) sets it to the 25th of the month.

However, I did find another issue with the template and have corrected it above. The previous version did not properly handle dates after payday this month but before the 1st of next month.

The calendar-based option is not affected since it’s getting the date value from the current or next calendar event. However, because of that, it will return incorrect values if you have matching calendar events on the wrong day.