Better way to execute code at a specific time? - python

I need to execute code at exact time, for example 10:00:00.000.
while True:
now = datetime.utcnow()
if now.hour == 10 and now.minute == 0 and now.second == 0:
#execute code here
time.sleep(1)
So far it seems to work but if I launch the code for example one hour before launch I feel like there is a lag in the execution?
Is this the best to achieve what I want?

Using datetime and threading.Timer:
from datetime import datetime, time
from threading import Timer
def do_the_thing():
print("execute code here")
Timer(
(datetime.combine(
datetime.today(), time(10, 0, 0)
) - datetime.now()).total_seconds(),
do_the_thing
).start()
Since Timer runs in a background thread, your script can go on to do other things immediately, and do_the_thing will get called as soon as the timer is up.

Simply sleep for the total amount of time wanted:
target_date = datetime(day=12, month=12, year=2021, hour=10)
time.sleep((target_date - datetime.now()).total_seconds())

Related

Calculate time between now and a specific timepoint

I am trying to make a program in python that starts doing a task at a specific time every day. Because it will run forever when the pc is on I want to make it as light as I can. So instead of checking the time forever, I would like to check the time once and calculate how many seconds to sleep until the right time.
whatever mechansim you choose to alert you and run the script is up to you but in terms of calculating time you can use timedelta. So for example;
from datetime import datetime, timedelta
now = datetime.now()
tomorrow = now + timedelta(1)
So you can imagine now, all you'd have to do is convert the result to whatever format you want. (seconds, minutes, hours, etc)
You can
import time
startTime = time.time()
time.sleep(3600) # one hour from current time
if time.time() - startTime > 3600:
yourTask()
OR
from datetime import datetime, timedelta
import time
currTime = datetime.now()
futureTime = currTime+timedelta(hours = 2) # 2 hours from now, you also can specify days
time.sleep(futureTime-currTime)
#OR Just
time.sleep(timedelta(hours = 2))
yourTask()
That's the general idea of sleep and time function in python
To run the same function at the same time every day you can use the sched.scheduler class below or a solution that does not require that class, which I show afterwards and is somewhat simpler:
See the documentation for the Python Event Scheduler module sched (in part):
class sched.scheduler(timefunc=time.monotonic, delayfunc=time.sleep)
The scheduler class defines a generic interface to scheduling events. It needs two functions to actually deal with the “outside world” — timefunc should be callable without arguments, and return a number (the “time”, in any units whatsoever). The delayfunc function should be callable with one argument, compatible with the output of timefunc, and should delay that many time units. delayfunc will also be called with the argument 0 after each event is run to allow other threads an opportunity to run in multi-threaded applications.
scheduler.enterabs(time, priority, action, argument=(), kwargs={})
Schedule a new event. The time argument should be a numeric type compatible with the return value of the timefunc function passed to the constructor. Events scheduled for the same time will be executed in the order of their priority. A lower number represents a higher priority.
import datetime
import sched
import time
# number of seconds in:
HOURS_SECONDS = 3600
MINUTES_SECONDS = 60
def my_time_func():
date_and_time = datetime.datetime.now()
# convert time component to absolute seconds since midnight:
return date_and_time.hour * HOURS_SECONDS + date_and_time.minute * MINUTES_SECONDS + date_and_time.second
def my_sleep_func(t):
#print('sleeping', t, 'seconds')
time.sleep(t)
def do_work():
print('I am working!')
s = sched.scheduler(timefunc=my_time_func, delayfunc=my_sleep_func)
# schedule something to begin every day at (24-hour clock:)
EVENT_HOURS=9
EVENT_MINUTES=35
EVENT_SECONDS=0
first_time = True
while True:
now = datetime.datetime.now()
next_event_dt = datetime.datetime(now.year, now.month, now.day, hour=EVENT_HOURS, minute=EVENT_MINUTES, second=EVENT_SECONDS)
schedule_event = True
if first_time:
first_time = False
# maybe too late for initial schedule day:
if next_event_dt < now:
schedule_event = False
if schedule_event:
event = s.enterabs(time=EVENT_HOURS * HOURS_SECONDS + EVENT_MINUTES * MINUTES_SECONDS + EVENT_SECONDS, priority=1, action=do_work)
s.run()
delta = next_event_dt + datetime.timedelta(days=1) - datetime.datetime.now()
my_sleep_func(delta.total_seconds())
And if you do not want to use the sched.scheduler class:
import datetime
import time
# number of seconds in:
HOURS_SECONDS = 3600
MINUTES_SECONDS = 60
def my_sleep_func(t):
#print('sleeping', t, 'seconds')
time.sleep(t)
def do_work():
print('I am working!')
# schedule something to begin every day at (24-hour clock:)
EVENT_HOURS=10
EVENT_MINUTES=30
EVENT_SECONDS=0
first_time = True
while True:
now = datetime.datetime.now()
next_event_dt = datetime.datetime(now.year, now.month, now.day, hour=EVENT_HOURS, minute=EVENT_MINUTES, second=EVENT_SECONDS)
schedule_event = True
if first_time:
first_time = False
# maybe too late for initial schedule day:
if next_event_dt < now:
schedule_event = False
if schedule_event:
delta = next_event_dt - datetime.datetime.now()
t = delta.total_seconds()
if t > 0:
my_sleep_func(t)
do_work()
delta = next_event_dt + datetime.timedelta(days=1) - datetime.datetime.now()
my_sleep_func(delta.total_seconds())
If you want to make sure that you work function runs on the initial day even if your program starts after the starting time for the event, then change your loop to the following (a similar change can be made if you are using the sched.scheduler class):
while True:
now = datetime.datetime.now()
next_event_dt = datetime.datetime(now.year, now.month, now.day, hour=EVENT_HOURS, minute=EVENT_MINUTES, second=EVENT_SECONDS)
delta = next_event_dt - datetime.datetime.now()
t = delta.total_seconds()
if t > 0:
my_sleep_func(t)
do_work()
delta = next_event_dt + datetime.timedelta(days=1) - datetime.datetime.now()
my_sleep_func(delta.total_seconds())
Needless to say (but I will say it anyway), my_sleep_func is just a time.sleep replacement with the ability to print out some diagnostics if you uncomment out the print statement.

How to make a function run for specific duration periodically

I want to take a screenshot every second for 10 secs.
I have tried using threading and schedule but I've not been able to come up with the solution to satisfy my problem.
def fun(original):
end_time = datetime.now() + timedelta(seconds=10)
while datetime.now() < end_time:
current = ImageGrab.grab()
current.save("current.png")
current = cv2.imread("current.png")
found = screenshot_comparison(original,current)
if found :
print("matched")
else :
print("didntMATCH")
fun(original)
I want to take screenshots every second for 10 secs and match it with an already grabbed screenshot.
I would suggest utilizing the Advanced Python Scheduler and more specifically, use their interval scheduler, for example:
sched = BlockingScheduler()
sched.add_job(yourFunction, 'interval', seconds=10)
sched.start()
EDIT
Here's a more complete example:
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
def myFunction(testParam):
print("Message: {}".format(testParam))
if __name__ == '__main__':
sched.add_job(myFunction, 'interval', seconds=10, args=["Works!"])
sched.start()

Make python script execute some functions every hour

So lets say i have this code:
...
connect()
find_links()
find_numbers()
in fact what it does is login to an account,get some numbers and one link:
example:
1.23, 1.32 , 32.1, 2131.3 link.com/stats/
1.32, 1.41 , 3232.1, 21211.3 link.com/stats/
so all i want to do is make these functions run every one hour
and then print the time so i can then compare results.I tried:
sched = BlockingScheduler()
#sched.scheduled_job('interval', seconds=3600 )
def do_that():
connect()
find_links()
find_numbers()
print(datetime.datetime.now())
but this just executes one time the functions and then just prints the date.
This should call the function once, then wait 3600 second(an hour), call function, wait, ect. Does not require anything outside of the standard library.
from time import sleep
from threading import Thread
from datetime import datetime
def func():
connect()
find_links()
find_numbers()
print(datetime.now())
if __name__ == '__main__':
Thread(target = func).start()
while True:
sleep(3600)
Thread(target = func).start()
Your code may take some time to run. If you want to execute your function precisely an hour from the previous start time, try this:
from datetime import datetime
import time
def do_that():
connect()
find_links()
find_numbers()
print(datetime.now())
if __name__ == '__main__':
starttime = time.time()
while True:
do_that()
time.sleep(3600.0 - ((time.time() - starttime) % 3600.0))

Best way to implment timeout for a while loop

I have a while loop
while somecondition:
dostuff
(Sorry. It is hard to give an executable example as this is part of a larger project).
Most of the time the condition is met after a short while and the loop expires. But sometimes the condition will never be met. How can I best catch such cases? Is a timer the best option? How can I implement it best?
You can use a timeout using SIGALRM. Here's a little program that demonstrates it.
import sys
import time
import signal
class TimeoutError(Exception):
pass
def _sig_alarm(sig, tb):
raise TimeoutError("timeout")
def main(argv):
timeout = 7
signal.signal(signal.SIGALRM, _sig_alarm)
try:
signal.alarm(timeout)
while True:
print("sleeping...")
time.sleep(1)
except TimeoutError:
pass
print("Out of loop.")
main(sys.argv)
This sets up a signal handler that simply raises a custom exception (but you can use any), and then catches it.
wait for an hour example
from datetime import timedelta
delete_TO = 1
wait_until = datetime.now() + timedelta(hours=delete_TO)
break_loop = False
while not break_loop:
do-your loop-stuff
if wait_until < datetime.now() or somecondition:
break_loop = True
(edited: wait_until must be smaller than datetime.now() )
The correct answer is
from datetime import timedelta
delete_TO = 1
wait_until = datetime.now() + timedelta(hours=delete_TO)
break_loop = False
while not break_loop:
do-your loop-stuff
if wait_until < datetime.now() or somecondition:
break_loop = True
This code is copy pasted from #ohad_the_lad (https://stackoverflow.com/users/2468201/ohad-the-lad) answer, but it fixes the unintentional bug where the loop exits if wait_until is greater than datetime.now() which will always happen.
How about writing a for loop? Or you can implement something like timer=0 an increment it every time you pass the loop. For example if you wanted to break after 100 iterations you could write an if statement. If timer == 100 then break.

executing specific statement at a given rate in python

I want to write a code which execute a statement specified number of times per second,
Many of you might be familier about the term rate
Here i want rate to be 30 per second
say i want to execute a function 30 times per second for 60 seconds
means rate=30/sec duration=60sec
Can any one tell me is their any api available in python to do the same ?
The sched module is intended for exactly this:
from __future__ import division
import sched
import time
scheduler = sched.scheduler(time.time, time.sleep)
def schedule_it(frequency, duration, callable, *args):
no_of_events = int( duration / frequency )
priority = 1 # not used, lets you assign execution order to events scheduled for the same time
for i in xrange( no_of_events ):
delay = i * frequency
scheduler.enter( delay, priority, callable, args)
def printer(x):
print x
# execute printer 30 times a second for 60 seconds
schedule_it(1/30, 60, printer, 'hello')
scheduler.run()
For a threaded environment, the use of sched.scheduler can be replaced by threading.Timer:
from __future__ import division
import time
import threading
def schedule_it(frequency, duration, callable, *args, **kwargs):
no_of_events = int( duration / frequency )
for i in xrange( no_of_events ):
delay = i * frequency
threading.Timer(delay, callable, args=args, kwargs=kwargs).start()
def printer(x):
print x
schedule_it(5, 10, printer, 'hello')
Try using threading.Timer:
def hello():
print "hello, world"
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
You can use time.time() to do what you want:
import time
def your_function():
# do something...
while True:
start = time.time() # gives current time in seconds since Jan 1, 1970 (in Unix)
your_function()
while True:
current_time = time.time()
if current_time - start >= 1.0/30.0:
break
This will make sure that the delay between calls of your_function is very close to 1/30 of a second, even if your_function takes some time to run.
There is another way: using Pythons built-in scheduling module, sched. I never used it, so I can't help you there, but have a look at it.
After some time spending i discovered how to do it well i used multiprocessing in python to achieve it
here's my solution
#!/usr/bin/env python
from multiprocessing import Process
import os
import time
import datetime
def sleeper(name, seconds):
time.sleep(seconds)
print "PNAME:- %s"%name
if __name__ == '__main__':
pros={}
processes=[]
i=0
time2=0
time1=datetime.datetime.now()
for sec in range(5):
flag=0
while flag!=1:
time2=datetime.datetime.now()
if (time2-time1).seconds==1:
time1=time2
flag=1
print "Executing Per second"
for no in range(5):
i+=1
pros[i] = Process(target=sleeper, args=("Thread-%d"%i, 1))
j=i-5
for no in range(5):
j+=1
pros[j].start()
j=i-5
for no in range(5):
j+=1
processes.append(pros[j])
for p in processes:
p.join()

Categories