dbader / schedule

Python job scheduling for humans.
https://schedule.readthedocs.io/
MIT License
11.71k stars 960 forks source link

Start a repeating job at a specific time. #568

Open paudrow opened 1 year ago

paudrow commented 1 year ago

It's very nice that schedule has until, but it feels like the project is missing a from(or similarly named function). For example, if I want to run a job every minute between the hours of 10am and 2pm.

The syntax, with until, could be something like the following:

schedule.every().minute.from(10:00).until("14:00").do(job)

There is some ambiguity about what happens around midnight. I would think a reasonable option would be to

The best workaround that I can think of to get the from behavior is to schedule a job at a specific time to run once and have that job schedule other jobs that run until an until time. This is a bit clunky to me.

Thanks for the great library!

SijmenHuizenga commented 1 year ago

Hi @paudrow, thank you for the suggestion!

Currently .until will cancel the job whenever the time is reached. Cancelling means removing the job from the scheduler.

Assuming we want to keep the .until behavior as-is, the .from() could but the opposite: The job only starts running after the specified timestamp. We could have .from() accept the same type of arguments as .until(): datetime.datetime, datetime.timedelta, datetime.time, str.

    def after(
        self,
        after_time: Union[datetime.datetime, datetime.timedelta, datetime.time, str],
    ):
        Schedule job to start running only after the specified moment.

        The first execution is delayed until after_time is reached. If after_time
        is in the past, the `.after()` has no effect.

        :param until_time: A moment representing the earliest time a job can
           be run. If only a time is supplied, the date is set to today.
           The following formats are accepted:

           - datetime.datetime
           - datetime.timedelta
           - datetime.time
           - String in one of the following formats: "%Y-%m-%d %H:%M:%S",
             "%Y-%m-%d %H:%M", "%Y-%m-%d", "%H:%M:%S", "%H:%M"
             as defined by strptime() behaviour. If an invalid string format is passed,
             ScheduleValueError is thrown.

        :return: The invoked job instance

Examples using relative timestamps:

schedule.every().minute.from("10:00").do(job)
# Create job at 09:00: first run is the same day at 10:00
# Create job at 11:00: first run is the same day at 11:01 because it is already after today 10:00
# Create job at 23:59: first run is the same day at 00:00, next run at 00:01
# Create job at 00:01: first run is the same day at 10:00

Like this, the .from() only effects when the job start running. Does this correctly describe what you are thinking of?

paudrow commented 1 year ago

Does this correctly describe what you are thinking of?

@SijmenHuizenga, yes, exactly!

takingoff-nl commented 1 year ago

Yes, this is also exactly what I need! It would be great if this function could be implemented in schedule.