I'm trying to make a "alarm" for my classes and it does that when a certain hour comes it does something (in this case it just prints, and i will change that when the code works) and it repeats until next alarm.The problem here is that when i run the code 1 min before it prints it's time , and then it reaches the alarm time and it still prints the same and not not yet.
I want the code to keep running after the if statements. Here's the code:
from datetime import datetime
import time
now = datetime.now()
current_time = now.strftime("%H:%M")
today = now.strftime("%A")
cn = "22:14"
ing ="21:23"
day = {0:"Monday", 1:"Tuesday", 2:"Wednesday"
, 3:"Thursday", 4:"Friday", 5:"Saturday", 6:"Sunday"}
def mday():
if (today == day[0]) and (current_time == cn):
print("its time")
time.sleep(1)
mday()
else:
print("not yet")
time.sleep(1)
mday()
mday()
The main problem with your code (why it does not work at all), is that you do not update the values of the today and current_time variables. That you sleep for one second in each call to mday() does not affect these variables. You need to update them right at the entry to mday.
The second problem is that you have infinite recursion here. Infinite loops run forever, which is what you want, I guess. Infinite recursion, on the other hand, simply uses up the stack, and crashes you application. You would need to convert the recursive function mday to one with an infinite loop. To do that, place all the if statement from inside mday inside a forever loop: (while True:), and
also remove the two recursive calls from the end of the branches. You can also take the sleep calls out of the if - remove one of them, and place the other after the the content of the else block:
from datetime import datetime
import time
cn = "22:14"
ing ="21:23"
day = {
0:"Monday",
1:"Tuesday",
2:"Wednesday",
3:"Thursday",
4:"Friday",
5:"Saturday",
6:"Sunday"
}
def mday():
while True:
# Update current time values
now = datetime.now()
current_time = now.strftime("%H:%M")
today = now.strftime("%A")
# Print alarm/no-alarm message
if (today == day[0]) and (current_time == cn):
print("its time")
else:
print("not yet")
time.sleep(1)
mday()
There are many ways this code can be optimized, but the above will produce roughly the result you want.
Related
Complete newbie here so bare with me. I've got a number of devices that report status updates to a singular location, and as more sites have been added, drift with time.sleep(x) is becoming more noticeable, and with as many sites connected now it has completely doubles the sleep time between iterations.
import time
...
def client_list():
sites=pandas.read_csv('sites')
return sites['Site']
def logs(site):
time.sleep(x)
if os.path.isfile(os.path.join(f'{site}/target/', 'hit')):
stamp = time.strftime('%Y-%m-%d,%H:%M:%S')
log = open(f"{site}/log", 'a')
log.write(f",{stamp},{site},hit\n")
log.close()
os.remove(f"{site}/target/hit")
else:
stamp = time.strftime('%Y-%m-%d,%H:%M:%S')
log = open(f"{site}/log", 'a')
log.write(f",{stamp},{site},miss\n")
log.close()
...
if __name__ == '__main__':
while True:
try:
client_list()
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.map(logs, client_list())
...
I did try adding calculations for drift with this:
from datetime import datetime, timedelta
def logs(site):
first_called=datetime.now()
num_calls=1
drift=timedelta()
time_period=timedelta(seconds=5)
while 1:
time.sleep(n-drift.microseconds/1000000.0)
current_time = datetime.now()
num_calls += 1
difference = current_time - first_called
drift = difference - time_period* num_calls
if os.path.isfile(os.path.join(f'{site}/target/', 'hit')):
...
It ends up with a duplicate entries in the log, and the process still drifts.
Is there a better way to schedule the function to run every x seconds and account for the drift in start times?
Create a variable equal to the desired system time at the next interval. Increment that variable by 5 seconds each time through the loop. Calculate the sleep time so that the sleep will end at the desired time. The timings will not be perfect because sleep intervals are not super precise, but errors will not accumulate. Your logs function will look something like this:
def logs(site):
next_time = time.time() + 5.0
while 1:
time.sleep(time.time() - next_time)
next_time += 5.0
if os.path.isfile(os.path.join(f'{site}/target/', 'hit')):
# do something that takes a while
So I managed to find another route that doesn't drift. The other method still drifted over time. By capturing the current time and seeing if it is divisible by x (5 in the example below) I was able to keep the time from deviating.
def timer(t1,t2)
return True if t1 % t2 == 0 else False
def logs(site):
while 1:
try:
if timer(round(time.time(), 0), 5.0):
if os.path.isfile(os.path.join(f'{site}/target/', 'hit')):
# do something that takes a while
time.sleep(1) ''' this kept it from running again immediately if the process was shorter than 1 second. '''
...
I tried to make a timer by making a function, that should keep on running until it hit 0. I thought I could get it to loop, but I think it ended up skipping the first part of else
"(int(time) - int(1))" and just repeating the second numeral it got after - 1.
What i want it to do: Take the whole function and run it through until it reaches 0.
What it does: takes time -1 and keeps printing that until it reaches maximum recursion depth.
import time as tm
def Timer(time):
if time == '0':
print("done")
tm.sleep(3)
else:
print(int(time) - int(1))
Timer(time)
Timer(time)
Assuming time is not a global, you need to pass time as input into your function and modify it accordingly so that you will eventually reach your recursive base case of time == '0'. Currently you are just calling Timer() over and over without changing the time, so you are going to keep recursively calling Timer() until you reach maximum recursion depth as you indicated (printing the changed time is not actually changing the time).
import time as tm
def Timer(time):
if time == '0':
print("done")
else:
print(int(time) - 1)
tm.sleep(1)
time = str(int(time) - 1)
Timer(time)
Timer('4')
Try this
def Timer(time):
for i in range(time,0, -1):
print(time -1)
print("done")
Timer(10)
If you really want a timer, look at importing time and use time.sleep(10)
from time import time
def Timer(time):
for i in range(time,0, -1):
time.sleep(1)
print(time - 1)
print("done")
Timer(10)
I made some small alterations on your code. Though it's very similar, I fixed the missing parameter and removed all the variable type convertions, since it didn't seem necessarry. Here's what I created (of course, you may have to adapt the function calling and probably remove my input):
import time as tm
def Timer(time):
while (time>0):
tm.sleep(1)
time -= 1
print(time)
print("done")
tm.sleep(3)
time=int(input('Choose your time value: '))
Timer(time)
I'm making an alarm that adjusts according to traffic. After messing around a bit, I decided it would be best for the program to get data from the API every 15 minutes or so. However, I noticed that if the while loop condition was met while time.sleep() was active, it wouldn't break till the full duration of time.sleep() ended. Is there any way to have it break when the condition is met, even during time.sleep()? Thanks in advance!
while datetime.datetime.now() < self.wakeuptime: #refers to alarm time
resp = requests.get(url=url, params=param)
data = json.loads(resp.content)
simplifiedtime = datetime.datetime.strptime(data["routes"][0]["legs"][0]["departure_time"]["text"], "%I:%M%p").time()
#gets suggested departure time from api
combinedsimplifiedtime=datetime.datetime.combine(today, simplifiedtime)
self.wakeuptime = combinedsimplifiedtime - datetime.timedelta(minutes=15)
#resets wakeuptime value depending on api
self.timetogo = combinedsimplifiedtime
print self.wakeuptime
time.sleep(900)
#waits 15 minutes and checks again until wakeuptime
You can use another while loop to check the current time much more frequently than the one that updates from the API. Instead of time.sleep(900) you can do:
start_pause = datetime.datetime.now()
while (datetime.datetime.now()-start_pause).seconds < 900 \
and datetime.datetime.now() < self.wakeuptime:
time.sleep(1)
This will still only run the outer loop after 900 seconds.
I'm wondering how I can play a .wav file after some time has passed without using the sleep function. Essentially, I was wondering if there is a way to keep track of time in Python, so that, after say 15 seconds has elapsed, I can play a sound without pausing my code.
# checks if I should play the sound or not and, sets the variable
def Tyler(self):
if self.started == 1:
if self.isTaiwan == 0:
if self.myListNames[self.current_player_id / 3].lower() == "tyler":
self.isTyler = 1
else:
self.isTyler = 0
self.Tyler()
if self.isTyler == 1:
time.sleep(6)
winsound.PlaySound("tyler.wav", winsound.SND_ASYNC)
# This is where I would want to check to see
# if some time has passed and the conditions haven't changed.
from time import time
def delay(secs):
init_time = time()
while time() < init_time+secs: pass
This won't use sleep but it is similar. Still uses time module
I've got this program:
import multiprocessing
import time
def timer(sleepTime):
time.sleep(sleepTime)
fooProcess.terminate()
fooProcess.join() #line said to "cleanup", not sure if it is required, refer to goo.gl/Qes6KX
def foo():
i=0
while 1
print i
time.sleep(1)
i
if i==4:
#pause timerProcess for X seconds
fooProcess = multiprocessing.Process(target=foo, name="Foo", args=())
timer()
fooProcess.start()
And as you can see in the comment, under certain conditions (in this example i has to be 4) the timer has to stop for a certain X time, while foo() keeps working.
Now, how do I implement this?
N.B.: this code is just an example, the point is that I want to pause a process under certain conditions for a certain amount of time.
I am think you're going about this wrong for game design. Games always (no exceptions come to mind) use a primary event loop controlled in software.
Each time through the loop you check the time and fire off all the necessary events based on how much time has elapsed. At the end of the loop you sleep only as long as necessary before you got the next timer or event or refresh or ai check or other state change.
This gives you the best performance regarding lag, consistency, predictability, and other timing features that matter in games.
roughly:
get the current timestamp at the time start time (time.time(), I presume)
sleep with Event.wait(timeout=...)
wake up on an Event or timeout.
if on Event: get timestamp, subtract initial on, subtract result from timer; wait until foo() stops; repeat Event.wait(timeout=[result from 4.])
if on timeout: exit.
Here is an example, how I understand, what your Programm should do:
import threading, time, datetime
ACTIVE = True
def main():
while ACTIVE:
print "im working"
time.sleep(.3)
def run(thread, timeout):
global ACTIVE
thread.start()
time.sleep(timeout)
ACTIVE = False
thread.join()
proc = threading.Thread(target = main)
print datetime.datetime.now()
run(proc, 2) # run for 2 seconds
print datetime.datetime.now()
In main() it does a periodic task, here printing something. In the run() method you can say, how long main should do the task.
This code producess following output:
2014-05-25 17:10:54.390000
im working
im working
im working
im working
im working
im working
im working
2014-05-25 17:10:56.495000
please correct me, if I've understood you wrong.
I would use multiprocessing.Pipe for signaling, combined with select for timing:
#!/usr/bin/env python
import multiprocessing
import select
import time
def timer(sleeptime,pipe):
start = time.time()
while time.time() < start + sleeptime:
n = select.select([pipe],[],[],1) # sleep in 1s intervals
for conn in n[0]:
val = conn.recv()
print 'got',val
start += float(val)
def foo(pipe):
i = 0
while True:
print i
i += 1
time.sleep(1)
if i%7 == 0:
pipe.send(5)
if __name__ == '__main__':
mainpipe,foopipe = multiprocessing.Pipe()
fooProcess = multiprocessing.Process(target=foo,name="Foo",args=(foopipe,))
fooProcess.start()
timer(10,mainpipe)
fooProcess.terminate()
# since we terminated, mainpipe and foopipe are corrupt
del mainpipe, foopipe
# ...
print 'Done'
I'm assuming that you want some condition in the foo process to extend the timer. In the sample I have set up, every time foo hits a multiple of 7 it extends the timer by 5 seconds while the timer initially counts down 10 seconds. At the end of the timer we terminate the process - foo won't finish nicely at all, and the pipes will get corrupted, but you can be certain that it'll die. Otherwise you can send a signal back along mainpipe that foo can listen for and exit nicely while you join.