DST-proofing: Time and Sun Automations
Make time- and sun-based automations resilient across DST changes using offsets, dedupe guards, and duration timers.
Search results
Why DST affects time and sun automations
Twice a year, clocks move forward or back. Time-based triggers at exact wall-clock times can be skipped (spring forward) or fire twice (fall back). Sun triggers are astronomical, so they continue to occur at the correct solar times, but any logic that combines sun events with fixed times may still be impacted.
Patterns that survive DST
1) Prefer sun events with offsets over fixed wall-clock times
Trigger relative to sunrise/sunset and add a small offset to match your preference. Offsets are applied to the astronomical event, not the local clock.
automation:
- alias: Lights on before sunset (DST-safe)
trigger:
- platform: sun
event: sunset
offset: "-00:30:00" # 30 minutes before sunset, works across DST
action:
- service: light.turn_on
target:
entity_id: light.living_room
2) Add a dedupe guard for exact-time triggers
If you must run at an exact time (for example, 07:00), add a guard to prevent a duplicate run during the fall DST overlap.
automation:
- alias: Run at 07:00 once even at DST fall-back
trigger:
- platform: time
at: "07:00:00"
condition:
# Only proceed if more than 55 minutes since the last run
- condition: template
value_template: >-
{{ (as_timestamp(now()) - as_timestamp(state_attr(this.entity_id, "last_triggered") or 0)) > 3300 }}
action:
- service: script.morning_routine
3) Use duration timers instead of sleeping across DST
When you need an exact duration (for example, run the fan for 90 minutes), prefer a Timer over
delay:. Timers measure elapsed real time and are not impacted by DST jumps.
# configuration.yaml (or UI equivalents)
timer:
bathroom_fan:
duration: "00:00:00" # duration set at start
automation:
- alias: Start fan for 90 minutes
trigger:
- platform: state
entity_id: binary_sensor.bathroom_humidity_high
to: "on"
action:
- service: timer.start
target:
entity_id: timer.bathroom_fan
data:
duration: "01:30:00"
- service: fan.turn_on
target:
entity_id: fan.bathroom
- alias: Stop fan when timer finishes
trigger:
- platform: event
event_type: timer.finished
event_data:
entity_id: timer.bathroom_fan
action:
- service: fan.turn_off
target:
entity_id: fan.bathroom
Why not a simple delay? A long delay: that crosses the DST change can end earlier or later than
expected on some systems, while timer keeps real elapsed duration.
4) Guard windowed schedules with time conditions
For schedules like “between 06:00 and 08:30”, use a time-window condition together with a DST-safe trigger (sun, sensor change, or time_pattern).
automation:
- alias: Heat boost on motion in morning window
trigger:
- platform: state
entity_id: binary_sensor.kitchen_motion
to: "on"
condition:
- condition: time
after: "06:00:00"
before: "08:30:00"
action:
- service: climate.set_temperature
target:
entity_id: climate.downstairs
data:
temperature: 21
5) Use time_pattern for periodic checks
time_pattern continues to tick through DST. Combine with a condition for precise control.
automation:
- alias: Check mail slot every 5 minutes (DST-safe)
trigger:
- platform: time_pattern
minutes: "/5"
condition:
- condition: state
entity_id: binary_sensor.mail_slot
state: "on"
action:
- service: notify.mobile_app_phone
data:
message: "Mail slot still open"
Troubleshooting around DST changes
- In Developer Tools States, inspect
sun.sunattributesnext_rising/next_settingto verify expected times. - Open an automation’s Trace to confirm whether it fired once or twice during the fall-back hour.
- If a time trigger was skipped (spring-forward), prefer a sun event or add a compensating
time_patterncheck plus conditions. - For sequences that must run exactly once, use the dedupe guard pattern or write to an
input_boolean/input_datetimeand check before acting.
Last modified November 20, 2025: DST-proofing: Time and Sun Automations (809e7e8)