diff --git a/twitchio/ext/routines/__init__.py b/twitchio/ext/routines/__init__.py index 65ed8f8e..d8068946 100644 --- a/twitchio/ext/routines/__init__.py +++ b/twitchio/ext/routines/__init__.py @@ -99,7 +99,7 @@ def __init__( self._args: tuple | None = None self._kwargs: dict | None = None - self.next_event_time:datetime.datetime|None = None #type : ignore + self.next_event_time: datetime.datetime | None = None def __get__(self, instance, owner): if instance is None: @@ -175,7 +175,7 @@ def cancel(self) -> None: Consider using :meth:`stop` if a graceful stop, which will complete the current iteration, is desired. """ if self._can_be_cancelled(): - self.next_event_time =None + self.next_event_time = None self._task.cancel() @@ -322,18 +322,19 @@ def completed_iterations(self) -> int: def remaining_iterations(self) -> Optional[int]: """A count of remaining iterations.""" return self._remaining_iterations - + @property - def time_till_execution(self) -> datetime.timedelta: - """Return the time left as a datetime object before the next execution.""" - + def next_execution_time(self) -> datetime.timedelta | None: + """Return the time left as a datetime object before the next execution. + + None will be returned if the routine is not scheduled + """ + if self.next_event_time is None: - #This might be misleading for stopped routines. Consider None return? - return datetime.timedelta(seconds=0) - # For long running routines (ie the action takes a while), - return max(self.next_event_time - datetime.datetime.now(),datetime.timedelta(seconds=0)) - - + return None + + return max(self.next_event_time - datetime.datetime.now(datetime.timezone.utc), datetime.timedelta(seconds=0)) + @property def start_time(self) -> Optional[datetime.datetime]: """The time the routine was started. @@ -370,7 +371,7 @@ async def _routine(self, *args, **kwargs) -> None: await asyncio.sleep(wait) if self._wait_first and not self._time: - self.next_event_time = self._delta+datetime.datetime.now() + self.next_event_time = self._delta + datetime.datetime.now(datetime.timezone.utc) await asyncio.sleep(self._delta) if self._remaining_iterations == 0: @@ -378,13 +379,6 @@ async def _routine(self, *args, **kwargs) -> None: while True: start = datetime.datetime.now(datetime.timezone.utc) - - # This will give a move accurate estimate during the sleep. HOWEVER - it will also be misleading as you could have a routine that runs longer than the sleep time - # as it would imply that a second invoke will be called during the execution of the current one - # if self._time: - # self.next_event_time = compute_timedelta(self._time + datetime.timedelta(days=self._completed_loops)) - # else: - # self.next_event_time = max(start + self._delta, 0) try: if self._instance: @@ -415,8 +409,9 @@ async def _routine(self, *args, **kwargs) -> None: sleep = max((start - datetime.datetime.now(datetime.timezone.utc)).total_seconds() + self._delta, 0) self._completed_loops += 1 - # I believe this will provide a more realistic capture of what is happening - self.next_event_time = datetime.datetime.now() + datetime.timedelta(seconds=sleep) + + self.next_event_time = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=sleep) + await asyncio.sleep(sleep) try: @@ -475,7 +470,7 @@ def routine( def decorator(coro: Callable) -> Routine: time_ = time - + if any((seconds, minutes, hours)) and time_: raise RuntimeError( "Argument