This question already has answers here:
How do I get a Cron like scheduler in Python?
(9 answers)
Closed 6 years ago.
I have a long running python script that I want to do someting at 01:00 every morning.
I have been looking at the sched module and at the Timer object but I can't see how to use these to achieve this.
I spent quite a bit of time also looking to launch a simple Python program at 01:00. For some reason, I couldn't get cron to launch it and APScheduler seemed rather complex for something that should be simple. Schedule (https://pypi.python.org/pypi/schedule) seemed about right.
You will have to install their Python library:
pip install schedule
This is modified from their sample program:
import schedule
import time
def job(t):
print "I'm working...", t
return
schedule.every().day.at("01:00").do(job,'It is 01:00')
while True:
schedule.run_pending()
time.sleep(60) # wait one minute
You will need to put your own function in place of job and run it with nohup, e.g.:
nohup python2.7 MyScheduledProgram.py &
Don't forget to start it again if you reboot.
You can do that like this:
from datetime import datetime
from threading import Timer
x=datetime.today()
y=x.replace(day=x.day+1, hour=1, minute=0, second=0, microsecond=0)
delta_t=y-x
secs=delta_t.seconds+1
def hello_world():
print "hello world"
#...
t = Timer(secs, hello_world)
t.start()
This will execute a function (eg. hello_world) in the next day at 1a.m.
EDIT:
As suggested by #PaulMag, more generally, in order to detect if the day of the month must be reset due to the reaching of the end of the month, the definition of y in this context shall be the following:
y = x.replace(day=x.day, hour=1, minute=0, second=0, microsecond=0) + timedelta(days=1)
With this fix, it is also needed to add timedelta to the imports. The other code lines maintain the same. The full solution, using also the total_seconds() function, is therefore:
from datetime import datetime, timedelta
from threading import Timer
x=datetime.today()
y = x.replace(day=x.day, hour=1, minute=0, second=0, microsecond=0) + timedelta(days=1)
delta_t=y-x
secs=delta_t.total_seconds()
def hello_world():
print "hello world"
#...
t = Timer(secs, hello_world)
t.start()
APScheduler might be what you are after.
from datetime import date
from apscheduler.scheduler import Scheduler
# Start the scheduler
sched = Scheduler()
sched.start()
# Define the function that is to be executed
def my_job(text):
print text
# The job will be executed on November 6th, 2009
exec_date = date(2009, 11, 6)
# Store the job in a variable in case we want to cancel it
job = sched.add_date_job(my_job, exec_date, ['text'])
# The job will be executed on November 6th, 2009 at 16:30:05
job = sched.add_date_job(my_job, datetime(2009, 11, 6, 16, 30, 5), ['text'])
https://apscheduler.readthedocs.io/en/latest/
You can just get it to schedule another run by building that into the function you are scheduling.
I needed something similar for a task. This is the code I wrote:
It calculates the next day and changes the time to whatever is required and finds seconds between currentTime and next scheduled time.
import datetime as dt
def my_job():
print "hello world"
nextDay = dt.datetime.now() + dt.timedelta(days=1)
dateString = nextDay.strftime('%d-%m-%Y') + " 01-00-00"
newDate = nextDay.strptime(dateString,'%d-%m-%Y %H-%M-%S')
delay = (newDate - dt.datetime.now()).total_seconds()
Timer(delay,my_job,()).start()
Related
When I click the arrow to run the python code, it simply executes.
However, if I select the option to run the code line-by-line, then the scheduled tasks will continually run as desired.
import datetime
from datetime import datetime, timedelta
import time
from apscheduler.schedulers.background import BackgroundScheduler
sched = BackgroundScheduler(daemon=True)
frequency = 10/60
def main_func(frequency):
start_time = datetime.now()
end_time = start_time + timedelta(minutes=frequency)
print("Start Time: ", start_time)
print("End Time: ", end_time)
if __name__ == "__main__":
sched.add_job(main_func, 'interval', [frequency], minutes=frequency)
sched.start()
(Undesired): Pressing Button in VSCode:
(Desired): Selecting All Code in script within VSCode, Right Clicking and Run Line-by-Line
Questions:
How can I run the python file so it behaves like I ran it line-by-line and doesn't immediately terminate?
Also, will that method work if I ran the python script from a task scheduler?
The answer to this question is is literally the first entry in the APScheduler FAQ.
The essence is that you're starting a background service and then letting the script run to the end which then exits the process. Use cases like these are what BlockingScheduler is for:
from datetime import datetime, timedelta
import time
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
frequency = 10/60
def main_func(frequency):
start_time = datetime.now()
end_time = start_time + timedelta(minutes=frequency)
print("Start Time: ", start_time)
print("End Time: ", end_time)
if __name__ == "__main__":
sched.add_job(main_func, 'interval', [frequency], minutes=frequency)
sched.start()
I made the following ,but it doesn't print the time.
from apscheduler.schedulers.background import BackgroundScheduler
from datetime import datetime
def tick():
print('Tick! The time is: %s' % datetime.now())
scheduler = BackgroundScheduler()
scheduler.add_job(tick,'interval',seconds=3)
print('starting')
scheduler.start()
print('stopped')
This is because your program is exiting before the interval has elapsed and needs to be kept alive at least until the first interval, consider using the following example:
while True:
#Thread activity here (time.sleep(2) for example)
or using other forms of activity to keep your main thread alive. Or just print out the time without this scheduling if that's what you really need.
My goal for this code is to ultimately make a timing routine for some lights. Essentially have a two fields that a user fills saying when a light should come on and when it should come off. I'm starting from ground zero right now so I'm trying to cover the basics.
I've gotten a timer down using code from another post:
from datetime import datetime
from threading import Timer
x=datetime.today()
y=x.replace(day=x.day, hour=1, minute=0, second=0, microsecond=0)
delta_t=y-x
secs=delta_t.seconds+1
def hello_world():
print "hello world"
#...
t = Timer(secs, hello_world)
t.start()
This prints hello world at a certain time everyday. The only problem with this code is that once it completes the routine, it does not restart. I'd like for one that continues refreshing. In addition to that, I'd like to print out a time every second. I tried using a while loop but I end up getting stuck in there so my hello world statement never actually prints:
from datetime import datetime
from threading import Timer
x=datetime.today()
y=x.replace(day=x.day+1, hour=1, minute=0, second=0, microsecond=0)
delta_t=y-x
secs=delta_t.seconds+1
def hello_world():
print "hello world"
#...
t = Timer(secs, hello_world)
t.start()
You can use run() to restart the thread:
def hello_world():
global t
print ("hello world")
t.run()
t = Timer(secs, hello_world)
t.start()
Than you can make a new thread
def hello_world():
global sec
print ("hello World")
Timer(sec,hello_word).start()
and you can also use a CRON job
Using python's schedule module how can I start a job at particular time and thereon it should be scheduled at regular intervals.
Suppose I want to schedule a task every 4 hours starting from 09:00 am.
schedule.every(4).hours.at("09:00").do(task) # This doesn't work
How to achieve the above?
You can convert the inner schedule (every 4 hours) into a separate function which would be called by the main schedule (fixed time). The inner schedule function would be the one calling your job function.
Example -
import schedule
import time
def job():
print "I am working" #your job function
def schedule_every_four_hours():
job() #for the first job to run
schedule.every(4).hour.do(job)
return schedule.CancelJob
schedule.every().day.at("09:00").do(schedule_every_four_hours)
while True:
schedule.run_pending()
time.sleep(1)
If you would like to kill the schedule based on your requirement read more here. Check here.
The above solution will not work if there are multiple schedules, as the schedule.CancelJob will cancel the other schedules on the pipe, better to use clear tag
import schedule
from datetime import datetime
import time
def task():
print 'I am here...',datetime.now()
def schedule_every_four_hours(clear):
if clear =='clear':
schedule.every(2).seconds.do(task).tag('mytask1') #for the first job to runschedule.every(4).hour.at("9:00").do(task)
else:
schedule.every(5).seconds.do(task).tag('mytask2') # for the second job to runschedule.every(4).hour.at("9:00").do(task)
print clear
schedule.clear(clear)
now = datetime.now()
times = str(now.hour+0)+ ":"+str(now.minute+1)
times1 = str(now.hour+0)+ ":"+str(now.minute+3)
schedule.every().day.at(times).do(schedule_every_four_hours,'clear').tag('clear')
schedule.every().day.at(times1).do(schedule_every_four_hours,'clear1').tag('clear1')
while True:
schedule.run_pending()
time.sleep(1)
Just as add on - because I was searching for a solution for this:
Start at a specific time
Have an interval
Exit at a specific time
import schedule
import time
from datetime import datetime as dt
def job():
now = dt.now()
dt_string = now.strftime('%Y-%m-%d %H:%M:%S')
print ("I am working " ,dt_string )#your job function
def schedule_every_four_hours():
job() #for the first job to run
schedule.every(2).minutes.until("09:46").do(job)
print(' 2 Minuten')
return schedule.CancelJob
schedule.every().day.at("09:29").do(schedule_every_four_hours)
while True:
schedule.run_pending()
time.sleep(1)
I am trying to schedule a job in python using the APScheduler package. This answer looked great, but it's snytax is out of date. I went to user guide for the current version 3, but I cannot find a basic example where I can pass a datetime object to the scheduler like in the linked answer.
from datetime import date
from apscheduler.schedulers.background import BackgroundScheduler as Scheduler
from datetime import datetime
# Start the scheduler
sched = Scheduler()
sched.start()
# Define the function that is to be executed
def my_job(text):
print text
#Schedule job
job = sched.add_job(my_job, next_run_time = datetime(2015, 5, 11, 1, 05, 5), args = ['Hello World!'])
This yields the error: No handlers could be found for logger "apscheduler.executors.default".