How can I repeat something for x minutes in Python? - python

I have a program (temptrack) where I need to download weather data every x minutes for x amount of hours. I have figured out how to download every x minutes using time.sleep(x*60), but I have no clue how to repeat this process for a certain amount of hours.
UPDATE:
Thank you to everyone who posted a solution.
I marked the example using "datetime.datetime.now() + datetime.timedelta(hours=x)" as the best answer because I could understand it the best and it seems like it will work very well for my purpose.

Compute the time you want to stop doing whatever it is you're doing, and check each time that the time limit hasn't expired. Like this:
finish_time = datetime.datetime.now() + datetime.timedelta(hours=6)
while datetime.datetime.now() < finish_time:
do_something()
sleep_for_a_bit()

I've just found sched in the Python standard library.

You are looking for a scheduler.
Check this thread.

May be a bit of overkill, but for running background tasks, especially if you need a GUI, I'd recommend checking out the PyQt route with QSystemTrayIcon and QTimer

Maybe I'm misunderstanding you, but just put it in a loop that runs a sufficient number of times. For example, to download every 5 minutes for 2 hours you need to download 24 times, so:
for i in range(24):
download()
sleep(5*60)
If you need it to be parameterizable, it's just:
from __future__ import division
from math import ceil
betweenDLs = 5 # minutes
totalTime = 2*60 # minutes
for i in range(int(ceil(totalTime/betweenDLs))):
download()
sleep(betweenDLs*60)

Related

I'm trying to send a message using telebot python every month in 28th [duplicate]

I have a script that runs every 30 minutes but there is a section I just want to run on the first of the month at 2:00 am. I am using schedule in Python and I can't figure out how to set it for day 1 of the month.
month doesn't seem to be in the defined parameters of schedule to do something like schedule.every().month.at("02:00").do(job2)
Any suggestions? I am using python 2.7
Simplified code:
from safe_schedule import SafeScheduler
import time
def job():
print "I'm working...",
return
def scheduler():
# Schedule every30min routines
print 'Starting Scheduler'
scheduler = SafeScheduler()
scheduler.every(30).minutes.do(job)
#scheduler.every().month.at("02:00").do(job2)
while True:
scheduler.run_pending()
time.sleep(1)
if __name__ == '__main__':
scheduler()
The main contributor of the library discourages this sort of thing, see https://github.com/dbader/schedule/issues/73#issuecomment-167758653.
Yet, if one insists, one can schedule a daily job but run it only if it's the 1st of the month.
from datetime import date
from safe_schedule import SafeScheduler
def job2():
if date.today().day != 1:
return
# actual job body
scheduler = SafeScheduler()
scheduler.every().day.at("02:00").do(job2)
Another alternative is described in one of the issue comments https://github.com/dbader/schedule/issues/73#issuecomment-356769023.
EDIT :
They mention something about this in many issues of the project but a clean solution doesn't seem to exist yet. Also the whole project doesn't seem to be active anymore so I don't think this feature will be implemented anytime soon.
IMO you need to check manually if the current day is the first day of the month in your job in order to do this.
ORIGINAL ANSWER (which is wrong):
I've looked at the documentation and you are right, there isn't any mention of month:
https://schedule.readthedocs.io/en/stable/api.html#schedule.Scheduler
But there is an issue opened on the project that mentions just that:
https://github.com/dbader/schedule/issues/73
You can do this:
scheduler.every().day.if(lambda d,t: d.day == 1 and t.hour == 2).do(x)
I didn't see any mention of Windows Task Scheduler, here, but that could definitely work for you, if you are on Windows, of course.
https://www.digitalcitizen.life/how-create-task-basic-task-wizard

Question with python, music and events, is there a more elegant way of programming this?

Goal: To create a program that will be able to turn off and on lights to music based on events that are triggered from midi notes.
Hello all, I am hoping that this isn't too broad of a question to ask. I am working on a project where I get events from a midi file and turn those events into time. I take a note from the midi file and append it to a list as the time it was placed
Example:
https://imgur.com/swZsrk9
I take all of those and place them into a list. Don't worry about how I do that as that is not my main goal to discuss. I've just substituted the list with a hard-coded one on my example code.
I now have a list of times that I want lights to either turn on or off, now I just need to set an infinite loop with a timer that starts at 0 seconds (with the start of the song) and when the timer == (the next time in the list) it will print out a line. Here is my code:
import socket
import sys
import random
import time
from pygame import mixer
from mido import MidiFile
masterList = [12.37, 14.37, 15.12, 15.62,16.36, 17.61, 18.11, 19.11, 19.61, 20.35,]
mixer.init()
song = mixer.Sound('song.wav')
startTime = time.time()
endTime = startTime + song.get_length()
print(masterList)
print('Starting song.')
song.play()
print('Playing song, timer:',startTime)
while time.time() <= endTime:
#print(round(time.clock(),1),masterList[0])
if round(time.clock(),2) == masterList[0]:
print(round(time.clock(),2),"<-",masterList[0],"------------------")
del masterList[0]
#print('playing...')
time.sleep(.01)
mixer.quit()
Here is a video of it runing:
https://www.youtube.com/watch?v=VW-eNoJH2Wo&feature=youtu.be
Ignore the deprecation warnings
It works but sometimes, due to the nature of programming, the time.clock() does not always == the next item in the list. I knew that this would be a problem going in as you can't rely on how long the code takes to execute. Sometimes it takes a few more milliseconds than usual to complete a while loop so then when you call the time.clock() method it != the next time in the list. Then the list does not remove it's first item and then it will never equal that first item.
I tried going by 10 milliseconds (.1) but it doesn't give me the accuracy I need.
Also, it seems clunky, sometimes the events are delayed a few milliseconds and it makes the effect not as pleasing. As you can see from my video the times of the prints aren't lined up completely where they need to be, even though they are perfectly placed on where they need to be in the midi file.
Question: Is there a more elegant way of tackling this? I seem to keep finding ways of patching it to work better and then it always goes back to the nature of programming, where the cpu always is unreliable. I've been trying to think of different ways of doing this but I can't come up with any. Your help would be much appreciated!!
Since you're deleting the notes as you play them, have you tried using >= instead of ==?
E.g.,:
while time.time() <= endTime:
#print(round(time.clock(),1),masterList[0])
if round(time.clock(),2) >= masterList[0]:
print(round(time.clock(),2),"<-",masterList[0],"------------------")
del masterList[0]
That way the note will play as soon as possible after the specified time, and remove it from the queue. Only way to know actual performance is to test it, but at the very least it won't skip notes.

How to set a cron job on Skygear to run every 12 hours?

Trying to set a cron job on my Skygear python cloud code, but not sure what I should enter in the decorator. I only know that it will work for units in second, but how to schedule a job to run every 12 hours? It is hard to calculate the seconds every time.
My code is like this, the function is to call a POST request:
#skygear.every('#every 43200s')
def post_req():
print ('scheduled to run every 12 hours')
url = myurl
ref = something
r = requests.post(myurl, data = {'token':some_token, 'ref':something})
It actually works but is there some ways to write in a better format?
It seems like skygear.every also accepts crontab notation… so 0 */12 * * * could also do the trick.
Edit: Reading the robfig/cron docs, the best solution would actually be just #every 12h

Dynamic Python Countdown Timer

Beginner amateur Python scripter here (sorry if I unwittingly use incorrect terms). I'm looking to create a countdown timer in Python that takes into account a set date in the future and the current date.
For example, if I wanted to make a "deathclock" (to wit, a countdown timer that counts down to my estimated date of death) the timer would need to count down from the current date to my estimated date of death years in the future, the latter of which would be hard-coded into the Python script.
I imagine I'd have to do something like get the current date, convert it to seconds, subtract it from the date of death (which would also be converted to seconds), and then convert the difference to a years-months-days-hours-minutes-seconds format, which would then be the starting point of the countdown timer (the timer would preferably need to be able to display years, months, days, hours, minutes, and seconds as it counts down).
Is there a relatively simple way to do this so the timer displays in a Linux terminal, or would doing something like this be a pain?
Thanks in advance for any assistance.
You can get the delta between two times:
from datetime import datetime
my_death = datetime(2044, 3, 24)
lacking = datetime.now() - my_death
This lacking object has some useful attributes you can use, like lacking.days and lacking.total_seconds().
You have to tell the terminal to overwrite the current line instead of printing to a new line.
This will only work on systems that properly handle control characters. It works from a Windows command prompt and I just tested on OSX but doesn't from Idle.
import sys,time
def msg(txt):
sys.stdout.write(txt)
sys.stdout.flush()
for sec in range(10):
time.sleep(1)
m = "%2d seconds" % (10-sec)
msg(m + chr(13))
Regarding the time operations, you can use the datetime module which lets you compute and format date intervals (like +3 days). https://docs.python.org/2/library/datetime.html

Is there a possibility to modify the reruns per second of a while-loop? (Python) [duplicate]

This question already has answers here:
How do I ensure that a Python while-loop takes a particular amount of time to run?
(3 answers)
Closed 9 years ago.
I have the following problem: I need a program that runs every minute. I have managed to do this with python's time-module and an infinite while-loop. It looks like this:
while True:
time_now = tm.gmtime(tm.time())
min_now = time_now.tm_min
if min_now - min_then == 1 or min_now - min_then == -59:
min_then = min_now
......
The loop runs about 150.000 times a second and while I don't think that the general performance is harmed worthy of mention, I wonder if there are alternatives.
Can I modify the number of reruns of a while loop? Or does the algorithm (in assembler, machine code etc.) just jump back to the beginning when finished? Can I use something like a 'wait'-command and will that help?
Thanks for listening (and answering ;) ),
best wishes,
Max
EDIT:
A sleep-command indeed solved my problems. I forget to mention that the rerun must take place every full clock-minute. A sleep for 60 seconds wouldn't be satisfying, however, I used a way that Xi Huan's link mentioned: After the execution of a loop, I use sleep(59.9-time_now.tm_sec). That reduces the CPU usage to 1%. Excellent.
And: Thank you all for your help! I'd like to upvote you, but I don't have enough reputation :D sry
bye!
An easy way would be to sleep in the loop, e.g.
import time
while True:
# do some stuff
time.sleep(60) #sleeps for a minute
EDIT:
Also be aware that you will need to 'import time' for this to work. Also, if you wish to limit the number of times it loops, this could be useful. The example below will loop once per minute and will loop 10 times in total.
import time
for x in xrange(0, 10):
#do stuff
time.sleep(60)
A common way to do this is by calling time.sleep, which is essentially the 'wait' command you ask about. If you do:
while True:
time.sleep(60)
# do stuff
The loop will end up running approximately once every minute, plus however long the do stuff takes. There are caveats mentioned in the docs that this isn't guaranteed to be an exact wait time, so you probably still want to check the time at each iteration (depending how strict the 'once per minute' is).
use a time.sleep method:
import time
while True:
#do something
time.sleep(60)

Categories

Resources