Skip to content

Conversation

@cebtenzzre
Copy link
Contributor

@cebtenzzre cebtenzzre commented Dec 28, 2025

appdaemon 4.3.0b1 in commit fb6a150 ("run_at() support for times that have already passed") introduced a feature to allow run_at to be passed times that have already passed on the current day (so the next occurrence would be tomorrow). And run_daily had always worked that way. It seems like by 4.5.0, this behavior of run_at had been broken in a refactor.

run_at() on the latest release executes callbacks immediately when given a time in the past, instead of scheduling them for the next day as documented.

Problem

When calling run_at() with a time that has already passed today, the callback would fire immediately instead of being scheduled for tomorrow:

# At 13:46, this was firing immediately instead of scheduling for tomorrow at 13:45
self.run_at(self.callback, "13:45:00")  

# Same issue with time objects
self.run_at(self.callback, datetime.time(13, 45, 0))

This contradicts the documented behavior which states: "If the time specified is in the past, the callback will occur the next day at the specified time."

Root Cause

This is a regression introduced in version 4.5.0 by commit ccf7b18 ("positional argument support and fixed sunrise/sunset calculations").

Old behavior (pre-4.5.0):

# run_at explicitly checked if time was in past and added a day
if aware_when < now:
    aware_when += timedelta(days=1)

New behavior (4.5.0+):

# Delegated to parse_datetime without specifying today parameter
start = await self.AD.sched.parse_datetime(start, aware=True)
# With today=None (default), past times stayed on today's date

The refactor delegated time parsing to parse_datetime() but didn't explicitly tell it that run_at() needs times to always be in the future. The today parameter defaults to None, which allows times to be in the past (appropriate for elevation events, but not for run_at()).

Solution

Updated run_at() to explicitly pass today=False when calling parse_datetime():

# For run_at, always schedule for the next occurrence (today=False)
# This ensures that times in the past are scheduled for tomorrow
start = await self.AD.sched.parse_datetime(start, aware=True, today=False)

Fixes #2491

@cebtenzzre cebtenzzre changed the title fix run_at and run_daily when the next occurrence is tomorrow fix run_at when the next occurrence is tomorrow Dec 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

run_at running immediately if start in past

1 participant