CalDAV/calendar.get_events using incorrect time zone in template

I have a sensor grabbing the day’s events from CalDAV.

- trigger:
    trigger: time_pattern
    hours: /12

  action:
    - action: calendar.get_events
      data:
        start_date_time: "{{ today_at('00:00:00') }}"
        end_date_time: "{{ today_at('23:59:59') }}"
      target:
        entity_id: calendar.ours
      response_variable: agenda_today

  sensor:
    - name: Daily Agenda
      unique_id: agenda_today
      state: "{{ agenda_today['calendar.ours'].events | count() }}"
      attributes:
        agenda_today: "{{ agenda_today['calendar.ours'].events }}"
      icon: mdi:calendar

This then gets passed to assist for a daily briefing with this template:

    Calendar events today: {% set agenda = state_attr('sensor.daily_agenda',
    'agenda_today') %} {% if agenda %}
      {% for event in agenda %}
        {% if event.summary %}
          Event: {{ event.summary }} 
          Location: {% if event.location %}{{ event.location }}{% endif %}
        {% endif %}
      {% endfor %}
    {% else %}
      There are no events for today.
    {% endif %}

Overall it works well, but I struggle with all-day events due to the time zone offset (I am on Eastern US time). CalDAV sees an all-day event tomorrow (April 11) as from April 10 at 8PM to April 11 at 8PM, rather than April 11 from 12AM to 11:59PM. I think this is where the problem stems from, because it is passing tomorrow’s event to the Daily Agenda sensor as if its starting today.

So when I look at the attributes for the CalDAV sensor, I see this:

Attributes
Message         Garbage Day!
All day             Yes
Start time         April 10, 2025 at 8:00:00 PM
End time          April 11, 2025 at 8:00:00 PM

How can I adjust the start_date_time and end_date_time, or the time offset for CalDAV, so my sensor properly reads out only the events happening on that day?

I’ve tried a few different options and had no luck:

start_date_time: "{{ now().astimezone().strftime('%Y-%m-%d 00:00:00') }}"
end_date_time: "{{ now().astimezone().strftime('%Y-%m-%d 23:59:59') }}"

and

start_date_time: "{{ now().astimezone().replace(hour=0, minute=0, second=0, microsecond=0).isoformat() }}"
end_date_time: "{{ now().astimezone().replace(hour=23, minute=59, second=59, microsecond=999999).isoformat() }}"

I could not reproduce the problem you reported.

I have an all-day event scheduled on April 23rd (12 days from today) in Apple Calendar (accessed via CalDAV). It’s the only event on that day.

I used the following actions in a script.

  - action: calendar.get_events
    target:
      entity_id: calendar.home
    data:
      start_date_time: "{{ today_at('00:00:00') + timedelta(days=12) }}"
      end_date_time: "{{ today_at('23:59:59') + timedelta(days=12) }}"
    response_variable: agenda
  - action: notify.persistent_notification
    data:
      title: test
      message: |
        {{ agenda['calendar.home'].events }}

The result contained one event with four fields:

  • start
  • end
  • summary
  • location

The values of start and end are 2025-04-23 and 2025-04-24, respectively. In other words, only dates and no times.

In your case, is CalDAV accessing Apple Calendar or something else?

Yes, CalDAV is accessing Apple Calendar. On my phone I turned on “Time Zone Override” to force it to New York time, but it had no effect on the CalDAV attributes in HA.

I created the same script you used and I got this as the output (redacted event info):

[{'start': '2025-04-15', 'end': '2025-04-16', 'summary': 'Event 1', 'location': 'location'}, {'start': '2025-04-15', 'end': '2025-04-16', 'summary': 'Event 2'}, {'start': '2025-04-14', 'end': '2025-04-15', 'summary': 'Event 3'}]

Today is 4/14, so it should only be showing event 3. For some reason its grabbing Event 1 and 2 even though they’re happening tomorrow.

A quick solution would likely just be to set my Home Assistant VM to UTC, but then I would have to adjust the time on all my other automations to correct this calendar offset.

I could also figure out how to make the template sensor look from yesterday at 8PM->today at 8PM, but there’s no

{{ yesterday_at('20:00:00') }}

option available.