Schedule task regularly at alternating times in python - python

I would like to schedule a task at minute :57 and minute :05, alternating every two hours. So the intervall during execution is alternating between 52 minutes and 68 minutes, on average 60 minutes.
For a given hour x the times when I would like to execute code are:
x:05; x:57; (x+2):05, (x+2):57; ...
I currently use the python module schedule and the following code:
schedule.every(2).hours.at(':05').do(job1)
schedule.every(2).hours.at(':57').do(job2)
while True:
schedule.run_pending()
time.sleep(1)
How can I best ensure that the code is not running at x:57 and then again at (x+1):05 the following hour (meaning the intervall is only 8 minutes long)?
Edit: I could add something along the lines of:
minutes = datetime.now().minutes
if not (minutes < 5 or minutes > 57):
time.sleep(60 - minutes)
and then schedule but I would miss 2 executions which is not ideal.

Related

How can i schedule my Code in Python at every 30 minutes increment after a particular time

I have a time - "09:20:45"
And I want to schedule my code after every 30 minutes of this time - "09:20:45".
I don't know how can I do this?
schedule.every(30).minutes.do(output_file_exporting)
while True:
schedule.run_pending()
time.sleep(1)
where output_file_exporting is my function name.
So I want to run my code after 09:20:45 on the increment of every 30 minutes
like -
09:50:45
10:20:45
10:50:45
11:20:45
11:50:45
on these time my code should be run.
You're making this harder than it needs to be. You just do it like you describe it.
import time
import datetime
while True:
now = datetime.datetime.now()
if now.hour >= 9 and now.minute in (20,50):
break
time.sleep(60)
output_file_exporting()
schedule.every(30).minutes.do(output_file_exporting)
...

How to add a component of randomness to a schedule

I am trying to schedule a job to run every 3 minutes on average, with a component of randomness between +/- 30 seconds. So the next job runs anywhere between 2mins 30secs - 3mins 30secs later.
This code works nicely for exactly 3 minutes, but I can't think of a way to introduce the 30 secs of randomness:
import schedule
def job:
print('hi')
schedule.every(3).minutes.do(job)
You need to look up the random module that comes with python.
import schedule
import random
def job():
print('hi')
two_mins_30 = 2 * 60 + 30
schedule.every(two_mins_30 + random.randint(0, 60)).seconds.do(job)
This calculation is: two minutes, 30 plus up to another minute at random.
Update:
It turns out you can directly do this with schedule because the Job class has a to() method:
schedule.every(two_mins_30).to(two_mins_30 + 60).seconds.do(job)

How to make the threading be executed following a fequencey (say, every 3 sec) at a (relatively) accurate time considering function execution time?

I want to run a function every 3 second, and I do have searched similar topics. However, I didn't find any solution that can indeed meet my requirement, and the key issue is that in these solutions, they do not consider the time of executing the function itself. Consider the following code.
import datetime as dt
import time
import threading
def counting():
global num
time_now = dt.datetime.now()
if num > 0:
print(f'count: {num}, time now: {time_now}')
num -= 1
t = threading.Timer(3.0, counting)
t.start()
num = 5
counting()
This prints every 3.0 seconds. The main issue is that in a real case, in stead of print(f'count: {num}, time now: {time_now}') , I will call a function, say, func1(), which will take some time between 1 second and 2.5 seconds. Hence, the real interval time between two calls will be more than 3 seconds (about 4-5.5 seconds). How can I write it to be exactly (of course, very small error is allowed) every 3 seconds between two calls? Thanks!
The way to do it is to use a monotonic clock to find out the current time, and subtract that from the time at which you next want your scheduled function to be called; then you know exactly how long you'll need to sleep for, regardless of how long your func1() took to execute. Here's an example (I removed the threading since the logic is the same regardless of whether it's running in the main thread or some child thread):
import random
import time
def func1():
seconds_to_sleep = random.randrange(1000, 2500) / 1000.0
print("pretending to work for %f seconds" % seconds_to_sleep)
time.sleep(seconds_to_sleep)
def scheduled_function(scheduled_time, now):
if (now > scheduled_time):
print("scheduled_function was called %f seconds late" % (now-scheduled_time))
else:
print("scheduled_function was called %f seconds early" % (scheduled_time-now))
next_call_time = time.monotonic() # schedule the first call to happen right away
while True:
now = time.monotonic()
time_until_call_time = next_call_time-now
if (time_until_call_time > 0.0):
time.sleep(time_until_call_time) # wait until our next scheduled call-time
scheduled_function(next_call_time, time.monotonic())
func1() # sleep for some unpredictable amount of time to simulate a workload
next_call_time = next_call_time + 3.0 # each call should happen ~3 seconds after the previous call
The solution using the Ada programming language is very simple. Ada provides a "delay until" syntax allowing to delay until some future time.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
with Ada.Calendar.Formatting; use Ada.Calendar.Formatting;
procedure Main is
task periodic;
task body periodic is
Now : Time;
Future : Time;
The_Delay : constant duration := 3.0;
begin
for I in 1..10 loop
Now := Clock;
Put_Line("Periodic message at time " & Image(Now));
Future := Now + The_Delay;
delay 1.0;
delay until Future;
end loop;
end periodic;
begin
null;
end Main;
A recent execution of this program results in the following output (Time is the UTC time zone):
Periodic message at time 2021-05-27 02:26:46
Periodic message at time 2021-05-27 02:26:49
Periodic message at time 2021-05-27 02:26:52
Periodic message at time 2021-05-27 02:26:55
Periodic message at time 2021-05-27 02:26:58
Periodic message at time 2021-05-27 02:27:01
Periodic message at time 2021-05-27 02:27:04
Periodic message at time 2021-05-27 02:27:07
Periodic message at time 2021-05-27 02:27:10
Periodic message at time 2021-05-27 02:27:13
The variable The_Delay is a constant value indicating 3.0 seconds. The Now time is the time at the beginning of each iteration. The Future time is Now plus 3.0 seconds. The resulting time is not offset by the task execution as long as that execution does not exceed 3.0 seconds. In order to simulate a long task execution the task delays (sleeps) 1.0 seconds during each iteration. The "delay 1.0;" statement is an absolute delay while the "delay until Future;" statement is a relative delay.
I guess I got the answer myself. We need to use schedule module. See the examples in https://schedule.readthedocs.io/en/stable/examples.html
The following is my test code.
import datetime as dt
import time
import threading
import schedule
def job():
print("I'm running on thread %s" % threading.current_thread())
print(dt.datetime.now())
time.sleep(2)
def run_threaded(job_func):
job_thread = threading.Thread(target=job_func)
job_thread.start()
schedule.every(6).seconds.do(run_threaded, job)
schedule.every(6).seconds.do(run_threaded, job)
schedule.every(6).seconds.do(run_threaded, job)
t_end = dt.datetime.now() + dt.timedelta(seconds = 20)
while dt.datetime.now() < t_end:
schedule.run_pending()
You can see that I am letting it run for every 6 seconds (by applying three multithread parallel computing), and I do let it sleep for 2 seconds in the function job() to replace the real running time. And from the output result, you will see that it runs every 6 seconds instead of 8 seconds!

How to write a while loop that will run base in hours

I'm creating a test for Google Assistant based on while loop. The code will play a long mp3 file and I'm try to identify if the assistant will do a false trigger and count how many times.
I'm running on pycharm/pytest and getting the trigger status by UIAutomator provided by Google.
import android
import time
play_music(music.mp3)
start_time = time.time()
trigger = 0
hours = 1
command_timeout = hours * 60 * 60
while trigger < 3 or time.time() - start_time < command_timeout:
if trigger_screen.is_in_screen():
trigger += 1
time.sleep(10)
stop_music()
The conditions to stop the loop is 3 false triggers or one hour of test, but the loop isn't stop after one hour of test, could someone help me?
You're using an or statement when you should be using an and statement:
while trigger < 3 and time.time() - start_time < command_timeout:
With your current code, the while loop only terminates when BOTH conditions are
False, when you really want it to terminate when either one or the other is False.
You need to swap the or in your code with and like shown below:
import android
import time
play_music(music.mp3)
start_time = time.time()
trigger = 0
hours = 1
command_timeout = hours * 60 * 60
while trigger < 3 and time.time() - start_time < command_timeout:
if trigger_screen.is_in_screen():
trigger += 1
time.sleep(10)
stop_music()
Bassically the code you wrote continues the loop as long as one of the conditions is met, which explains why your music continued to play (less than 3 triggers so the loop still runs)

Does Python Timer have some limitation for supported longest time?

import threading
import os
def shutdown():
os.system("shutdown -s")
# user setting zone!!!
hour = 0
minute = 20
sec = 0
# user setting zone!!!
total_sec = hour*3600.0 + minute*60.0 + sec - 60.0
if total_sec < 0:
total_sec = 0
print("The computer will be Shut Down in (%d hour, %d minute, %d second).\n" %(hour, minute, sec))
if total_sec >= 120:
temp_sec = total_sec - 120
threading.Timer(temp_sec, lambda: print("Last 3 minutes before shuting down the computer!!\n")).start()
else:
print("Less than 3 minutes before shuting down the computer!!\n")
threading.Timer(total_sec, shutdown).start()
The code is shown above. When I set a short time like 10 min, 20 min or a little longer, the script could work normally. But if I set the waiting time to a long time like 4 hours or 5 hours, the script could NOT work at all. Nothing would happen when the time is up. Could you pls point out why the error happens and guide me to fix it? Thanks in advance.
Have you actually timed it? You say it works normally, but does it actually shut the computer off in 10 minutes when set for 10 minutes, and not say 15+ minutes?
I ask because it looks like you have it set to give you a 3 minute warning. However then the timer resets because you use total_sec in "threading.Timer(total_sec, shutdown).start()" So when you set it for say 60 minutes, it gives you a warning at 57 minutes, then runs for another 60 minutes.
Therefore, I suspect if you let it run for 11 hours, when you set it for 5 hours, it would actually shutoff the computer.

Categories

Resources