I need to call a function, exactly 08:00, 18:00, 22:00 hours. I've created a example to test the comparison between hours. When the current time reaches one of those horary. Put in inside a While loop thinking this example would work as a stopwatch, but I think I'm wrong. How is the best way to compare those values?
currentH= dt.datetime.now().strftime("%H:%M:%S")
h = "16:15:10"
while True:
if(currentH==h):
print 'Ok'
print 'The current Hour is: '+h
import datetime as dt
import time
currentH= dt.datetime.now().replace(microsecond=0).time()
hrs = ['00:02', '12:00']
for i in range(len(hrs)):
h = [int(x) for x in hrs[i].split(':')]
h = dt.datetime.now().replace(hour=h[0], minute=h[1], second=0,microsecond=0).time()
hrs[i] = h
while True:
currentH = dt.datetime.now().replace(microsecond=0).time()
print(currentH)
if currentH in hrs:
print('Time is now',currentH)
time.sleep(1)
The biggest problem with your code is that you never call now() again inside the loop, so you're just spinning forever comparing the initial time to 16:15:10.
While we're at it: Why convert the time to a string for comparison instead of just comparing times?
But there are bigger problems with this design that can't be fixed as easily.
What happens if you check the time at 16:15, then go to sleep, then wake up at 16:25? Then now() never returns 16:15:10.
Also, do you really want to burn 100% CPU for 10 hours?
A better solution is to write a sleep_until function:
def sleep_until(target):
left = target - dt.datetime.now()
if left > dt.timedelta(seconds=0):
time.sleep(left.total_seconds())
(If you're using Python 2.7 or 3.4, it's a bit more complicated, because sleep will wake up early if there's a signal. But to handle that case, you just need to add a while True: loop around the whole thing.)
Now, the only tricky bit is working out the first time you need to sleep until, which isn't all that tricky:
waits = itertools.cycle(dt.timedelta(hours=wait) for wait in (10, 4, 10))
now = dt.datetime.now()
start = dt.datetime.combine(dt.date.today(), dt.time(hour=8))
for wait in waits:
start += wait
if start > now:
break
And now, we just loop over the waits forever, sleeping until each next time:
for wait in waits:
sleep_until(start)
print('Time to make the donuts')
start += wait
Or, of course, you could just grab one of the many scheduling libraries off PyPI.
Or just use your platform's cron/launchd/Scheduled Tasks API to run your script.
Related
I'm trying to finish my programming course and I'm stuck on one exercise.
I have to count how much time it takes in Python to create threads and whether it depends on the number of threads created.
I wrote a simple script and I don't know if it is good:
import threading
import time
def fun1(a,b):
c = a + b
print(c)
time.sleep(100)
times = []
for i in range(10000):
start = time.time()
threading.Thread(target=fun1, args=(55,155)).start()
end = time.time()
times.append(end-start)
print(times)
In times[] I got a 10000 results near 0.0 or exacly 0.0.
And now I don't know if I created the test because I don't understand something, or maybe the result is correct and the time of creating a thread does not depend on the number of already created ones?
Can U help me with it? If it's worng solution, explain me why, or if it's correct confirm it? :)
So there are two ways to interpret your question:
Whether the existence of other threads (that have not been started) affects creation time for new threads
Whether other threads running in the background (threads already started) affects creation time for new threads.
Checking the first one
In this case, you simply don't start the threads:
import threading
import time
def fun1(a,b):
c = a + b
print(c)
time.sleep(100)
times = []
for i in range(10):
start = time.time()
threading.Thread(target=fun1, args=(55,155)) # don't start
end = time.time()
times.append(end-start)
print(times)
output for 10 runs:
[4.696846008300781e-05, 2.8848648071289062e-05, 2.6941299438476562e-05, 2.5987625122070312e-05, 2.5987625122070312e-05, 2.5987625122070312e-05, 2.5987625122070312e-05, 2.5987625122070312e-05, 2.5033950805664062e-05, 2.6941299438476562e-05]
As you can see, the times are about the same (as you would expect).
Checking the second one
In this case, we want the previously created threads to keep running as we create more threads. So we give each thread a task that never finishes:
import threading
import time
def fun1(a,b):
while True:
pass # never ends
times = []
for i in range(100):
start = time.time()
threading.Thread(target=fun1, args=(55,155)).start()
end = time.time()
times.append(end-start)
print(times)
output:
Over 100 runs, the first one took 0.0003440380096435547 whereas the last one took 0.3017098903656006 so there's quite a magnitude of increase there.
Bright minds of Stackoverflow, I have a quest for you.
Currently I am running a loop in which calculations and data aquisition happen. These get more and more complicated over time. I want each run of the loop to last exactly one second. Due to the growing time of the calculations a simple "sleep(1)" at the end does not really help.
while True:
#here calculations happen that take more and more time
print 'some of the data'
sleep(1)
I was hoping to use datetime to calculate the seconds/milliseconds before these calculations and after to enter the difference into the sleep command. But i can't quite get my head around it. Can anyone help me out?
a=datetime.now()
#calculations
b=datetime.now()
calctime=(b-a).total_seconds()
sleep(1-calctime)
Try this:
from datetime import datetime
import time
def test():
a = datetime.now()
# calculations
b = datetime.now()
calctime = (b - a).total_seconds()
print("one")
time.sleep((1 - calctime) if (1-calctime)>0.0 else 0) #if your calculation already took 1 or more than 1 second then then make the waiting time 0
print("two")
test()
a=datetime.now()
#calculations
b=datetime.now()
calctime=b-a
ms = calctime.microseconds
if calctime.seconds == 0:
sleep(1-ms/1000000)
Additional info here: Python speed testing - Time Difference - milliseconds
I'd like to execute a function a random number of times each day between set periods. Here's what I have so far:
def get_epochtime(dt=datetime.now()):
EPOCH = datetime(1970, 1, 1)
return (dt - EPOCH).total_seconds()
def get_todays_run_schedule(runs_per_day, run_between):
now = datetime.now()
window_start = now.replace(hour=run_between[0])
window_end = now.replace(hour=run_between[1])
the_schedule = [ get_epochtime(radar.random_datetime(start=window_start, stop=window_end)) for t in range(randint(runs_per_day[0], runs_per_day[1])) ]
the_schedule.sort()
print("Today I will run %s times" % len(the_schedule))
for run_at in the_schedule:
print("I will run at " + time.strftime("%Y-%m-%d %H:%M", time.localtime(run_at)))
return the_schedule
# we will run between 2 and 4 times per day between the hours of 10 AM and 5 PM.
schedule = get_todays_run_schedule((2, 4), (10, 17))
while(True):
now = datetime.now()
nowsecs = get_epochtime(now)
if now.hour == 0 and now.minute == 0 and now.second == 0:
schedule = get_todays_run_schedule()
if nowsecs in schedule:
execute_my_function
sleep(1)
Basically the idea is that at midnight and at first run, we come up with a run schedule which is a list of epoch times, the length of which is between two supplied integers. Each second we check the time and if the current time is within the list of run times, we execute our function. Finally, we sleep until the next second.
However, it isn't working at all. I suspect this might be because my datetime objects somehow include microseconds which is throwing off the comparison, but it could be because of something I'm not understanding about the nature of date time comparisons in python.
It's true that microseconds will be a problem for you here—both the objects in your list and the now will have microseconds, and running a loop only about once/second, the chance of any of those nows exactly matching an event timestamp are pretty slim.
But even if you fix that by truncating both now and the values in the list to seconds, that still won't solve the problem, it'll just make it an intermittent problem that's harder to debug. Consider what happens if you have an event at 15:25:26, and you start the loop at 15:25:25.907. You truncate that to 15:25:25, look it up, it's not there. Then you sleep for about a second, and call now(), and you get, say, 15:25:27.033. You truncate that to 15:25:27, look it up, and it's not there either.
Since you've already sorted the list, you can do something a whole lot simpler, which I'll demonstrate below. But first: While we're at it, the whole point of datetime objects is that they can do time comparisons, arithmetic, etc. directly, so you don't need to convert everything to numbers with something like your get_epochtime.
yesterday = datetime.today() - datetime.timedelta(days=1)
while True:
now = datetime.now()
if now.date() > yesterday:
schedule = get_todays_run_schedule()
yesterday = now.date()
while schedule and now >= schedule[0]:
del schedule[0]
execute_my_function
sleep(1)
(Obviously you'll also need to change get_todays_run_schedule to return a list of datetime objects instead of a list of floats to do it this way, but you should be able to figure that out.)
Also, notice that this way, we always know the time until the next event, so we don't need to loop around sleep(1) and keep waking the computer every second while it's on battery. You can just sleep(schedule[0] - now) when there is a next event, or sleep until midnight when there isn't. Or, maybe more simply, generate tomorrow's schedule when schedule goes empty, and then just sleep until its schedule[0].
In fact, if you think about it, you should be able to figure how to turn this into a loop in this form:
while True:
schedule = make_today_or_tomorrow_schedule()
for event in schedule:
while datetime.now() < event:
sleep(event - datetime.now())
execute_my_function
I am new with writing python code and trying to execute code only once in specific time. Sort of polling the time.
Here I want to execute when it is 00:30 AM.
while True:
now = datetime.datetime.now()
if now.hour == 0 and now.minute == 30:
print "Hit" # will use this line to call another function or code
time.sleep(100)
time.sleep(5) # to avoid hogging up cpu
Using an infinite loop and sleep(100), 100 secs will be good enough to execute the print only once.
Is there any more robust way in python to do this?
Introduction
There certainly are alternatives to your implementation, but it all depends on the context. If you are not going to do any other work between <start of script> and <desired execution time> you could simply calculate the number of seconds between the two points, and sleep for that entire duration.
from datetime import datetime as dt, time as t
from time import sleep
def work ():
pass
target = dt.combine (dt.now (), t (hour=10,minute=36,second=30))
secs = (target - dt.now ()).total_seconds ()
One must be aware that using dt.now () and setting the time explicitly the way we are doing above might lead a negative number in secs if that time has already passed.
To compensate for what was mentioned, we will need to make sure that our scheduled execution is in the future (effectively adding one day to our target if we must wait until tomorrow):
import datetime as datetime_m
from datetime import datetime as dt, time as t
from time import sleep
...
target = dt.combine (dt.now (), t (hour=0,minute=30,second=0))
if (target < dt.now ()):
target += datetime_m.timedelta(days=1)
...
Running it in loop
If you are going to run this in a loop, simply increment the target by one day on every iteration, and there's no need to worry about triggering the same work twice.
import datetime as datetime_m
from datetime import datetime as dt, time as t
from time import sleep
def work ():
pass
target = dt.combine (dt.now (), t (hour=0,minute=30,second=0))
if (target < dt.now ()):
target += datetime_m.timedelta (days=1)
while True:
seconds_until_execution = (target - dt.now ()).total_seconds ()
sleep (seconds_until_execution) # wait
work () # execute
target += datetime_m.timedelta (days=1) # queue next
I'd like to create a revenue counter for the sales team at work and would love to use Python. E.g. Joe Bloggs shifts his target from 22.1 to 23.1 (difference of 1.0.) I'd like the counter to tick evenly from 22.1 to 23.1 over an hour.
I've created this script, which works fine for counting a minute (runs 2 seconds over the minute); however, when it's supposed to run for an hour, it runs for 47 minutes.
Question: Does anyone know why it runs faster when I set it to an hour? Is sleep.time inaccurate?
import time
def rev_counter(time_length):
time_start = (time.strftime("%H:%M:%S"))
prev_pp = 22.1
new_pp = 23.1
difference = new_pp - prev_pp
iter_difference = (difference / 100000.) # Divide by 100,000 to show 10 decimal places
time_difference = ((time_length / difference) / 100000.)
i = prev_pp
while i < new_pp:
print("%.10f" % i)
i = i + iter_difference
time.sleep(time_difference)
time_end = (time.strftime("%H:%M:%S"))
print "Time started at", time_start
print "Time ended at", time_end
rev_counter(60) # 60 seconds. Returns 62 seconds
rev_counter(600) # 10 minutes. Returns 10 minutes, 20 secs
rev_counter(3600) # 1 hour. Returns 47 minutes
Please note this quote from the Python documentation for time.sleep()
The actual suspension time may be less than that requested because any
caught signal will terminate the sleep() following execution of that
signal's catching routine. Also, the suspension time may be longer
than requested by an arbitrary amount because of the scheduling of
other activity in the system.
As a suggestion, if faced with this problem, I would use a variable to track the time that the interval starts. When sleep wakes up, check to see if the expected time has elapsed. If not, restart a sleep for the difference, etc.
First of all, your loop doesn't only contain sleep statements -- the things you do between calling time.sleep take time, too, so if you do 10 repetions, you'll spent only 10% of the time doing these compared to when you have 100 iterations through your loop.
Is sleep.time inaccurate?
Yes. Or well. Quite.
I come from a real-time signal processing background. PC clocks are only somewhat accurate, and the time you spend in your OS, your standard libraries, your scripting language run time and your scripting logic between the point in time when a piece of hardware notifies you that your time has elapsed and the point in time your software notices is significant.
I just noticed time.sleep taking way too long (5-30000 times longer for input values between .0001 to 1 second), and searching for an answer, found this thread. I ran some tests and it is consistently doing this (see code and results below). The weird thing is, I restarted, then it was back to normal, working very accurately. When code started to hang it was time.sleep taking 10000 times too long?!
So a restart is a temporary solution, but not sure what the cause is/ permanent solution is.
import numpy as np
import time
def test_sleep(N,w):
data = []
for i in xrange(N):
t0 = time.time()
time.sleep(w)
t1 = time.time()
data.append(t1-t0)
print "ave = %s, min = %s, max = %s" %(np.average(data), np.min(data), np.max(data))
return data
data1 = test_sleep(20,.0001)
Out: ave = 2.95489487648, min = 1.11787080765, max = 3.23506307602
print data1
Out: [3.1929759979248047,
3.121081829071045,
3.1982388496398926,
3.1221959590911865,
3.098078966140747,
3.131525993347168,
3.12644100189209,
3.1535091400146484,
3.2167508602142334,
3.1277999877929688,
3.1103289127349854,
3.125699996948242,
3.1129801273345947,
3.1223208904266357,
3.1313750743865967,
3.1280829906463623,
1.117870807647705,
1.3357980251312256,
3.235063076019287,
3.189779043197632]
data2 = test_sleep(20, 1)
Out: ave = 9.44276217222, min = 1.00008392334, max = 10.9998381138
print data2
Out: [10.999573945999146,
10.999622106552124,
3.8115758895874023,
1.0000839233398438,
3.3502109050750732,
10.999613046646118,
10.99983811378479,
10.999617099761963,
10.999662160873413,
10.999619960784912,
10.999650955200195,
10.99962306022644,
10.999721050262451,
10.999620914459229,
10.999532222747803,
10.99965500831604,
10.999596118927002,
10.999563932418823,
10.999600887298584,
4.6992621421813965]