Selora Homes Selora Homes

DST-proofing: Time and Sun Automations

Make time- and sun-based automations resilient across DST changes using offsets, dedupe guards, and duration timers.

Time Sun Dst Automation

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.sun attributes next_rising/next_setting to 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_pattern check plus conditions.
  • For sequences that must run exactly once, use the dedupe guard pattern or write to an input_boolean/input_datetime and check before acting.