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.
This is my code:
import datetime, time
def function():
start = datetime.now()
...
stop = datetime.now()
result = (stop - start).total_seconds()
return result
But when I execute it, it returns 0... why tho
If you don't need the date, you could just run the following:
import time
def function():
start_time = time.time()
time.sleep(5)
end_time = time.time()
print(f'Completed in: {end_time - start_time} seconds')
function()
As is, the code does not run at all and not return anything. Instead, I get an Attribute error:
AttributeError: module 'datetime' has no attribute 'now'
When I fix your code (from datetime import datetime) and run it, the result is
0:00:00
which is likely hours, minutes and seconds. That is with ... as the only command between start and stop.
If the ... part takes muss less than a millisecond, it may not be detected. I doubt that it takes 50 ms as stated by you in a comment (see also below).
Can I call the current time two times in one function?
Yes:
import time
from datetime import datetime
def function():
start = datetime.now()
time.sleep(.001)
stop = datetime.now()
result = stop - start
return result
print(function())
0:00:00.001994
As you see, at 1 ms sleep time, the measured time is off by ~100% and times are not accurate any more.
it does the right thing for me under Linux (5.3), i.e:
from datetime import datetime
(datetime.now() - datetime.now()).total_seconds()
evaluates to -8e-06 which is good. I'd therefore assume the timer used under your Windows system isn't very high precision. I'd suggest using time.perf_counter() for these sorts of short durations, datetime is more for when you care about obscure human things like months.
for example
from time import perf_counter
perf_counter() - perf_counter()
gives me approx -2.8e-7, so we've also reduced the duration of the call to a few hundred nanoseconds.
I am trying to print the current time before my normal prints
global begtime
begtime = str(datetime.datetime.now()).split('.')[0]
global secondtime
secondtime = begtime.split(' ')[1]
global time
time = '[' + secondtime + ']' + ':'
print time
datetime.datetime.now returns in the format of :
year.month.date hour.minute.second
so I first split at the '.' to get the individual times, then I split at the space to get just the time.
then I formatted it as [hour:min:sec]
It works, but the time is not correct, it will print same time for all prints even if they happen minutes apart.
I want the exact time for every print.
For your code, you're probably setting the time earlier in your program and then accessing it later thinking it is generating a new time. It won't generate a new time every time you print it. It will only generate a new time every time you run begtime = str(datetime.datetime.now()).split('.')[0]
The better way to do this would be to use Date.strftime(format). I've included an example of this below.
import datetime
import time
now = datetime.datetime.now()
print(now.strftime('[%I:%M:%S]'))
time.sleep(10)
now = datetime.datetime.now()
print(now.strftime('[%I:%M:%S]'))
This will print the current time and then 10 seconds after the current time after 10 seconds.
I'm trying to get a for loop to print the value of 'i' every 5 minutes
import threading
def f(i):
print(i)
threading.Timer(600, f).start()
for i in range(1,1000000000000):
f(i=i)
However, this method results in the code printing the value of i instantly since it calls 'f' as soon as it finds 'i'.
I know this is not the first time someone will ask, nor the last, but I can't get it to work on a for loop nested within a function.
I'm fairly new to Python and I'd appreciate any help.
How about just keeping track of how long has passed in the loop?
from timeit import default_timer as timer
start = timer()
freq = 5 * 60 # Time in seconds
last_time = 0.0
for i in range(int(1e8)):
ctime = timer()
if ctime - last_time > freq:
print(i)
last_time = ctime
I imagine you can make this more efficient by only checking the time every N iterations rather than every time. You may also want to look into using progressbar2 for a ready-made solution.
I prefer using datetime, as I think it's more intuitive and looks a bit cleaner. Otherwise, using more or less the same approach as Paul:
from datetime import datetime, timedelta
print_interval = timedelta(minutes=5)
# Initialize the next print time. Using now() will print the first
# iteration and then every interval. To avoid printing the first
# time, just add print_interval here (i.e. uncomment).
next_print = datetime.now() # + print_interval
for i in range(int(1e8)):
now = datetime.now()
if now >= next_print:
next_print = now + print_interval
print(i)
Also note that before python 3.x xrange would be preferable over range.
I know that I can cause a thread to sleep for a specific amount of time with:
time.sleep(NUM)
How can I make a thread sleep until 2AM? Do I have to do math to determine the number of seconds until 2AM? Or is there some library function?
( Yes, I know about cron and equivalent systems in Windows, but I want to sleep my thread in python proper and not rely on external stimulus or process signals.)
Here's a half-ass solution that doesn't account for clock jitter or adjustment of the clock. See comments for ways to get rid of that.
import time
import datetime
# if for some reason this script is still running
# after a year, we'll stop after 365 days
for i in xrange(0,365):
# sleep until 2AM
t = datetime.datetime.today()
future = datetime.datetime(t.year,t.month,t.day,2,0)
if t.hour >= 2:
future += datetime.timedelta(days=1)
time.sleep((future-t).total_seconds())
# do 2AM stuff
You can use the pause package, and specifically the pause.until function, for this:
import pause
from datetime import datetime
pause.until(datetime(2015, 8, 12, 2))
Slightly more generalized solution (based off of Ross Rogers') in case you'd like to add minutes as well.
def sleepUntil(self, hour, minute):
t = datetime.datetime.today()
future = datetime.datetime(t.year, t.month, t.day, hour, minute)
if t.timestamp() > future.timestamp():
future += datetime.timedelta(days=1)
time.sleep((future-t).total_seconds())
Another approach, using sleep, decreasing the timeout logarithmically.
def wait_until(end_datetime):
while True:
diff = (end_datetime - datetime.now()).total_seconds()
if diff < 0: return # In case end_datetime was in past to begin with
time.sleep(diff/2)
if diff <= 0.1: return
Building on the answer of #MZA and the comment of #Mads Y
One possible approach is to sleep for an hour. Every hour, check if the time is in the middle of the night. If so, proceed with your operation. If not, sleep for another hour and continue.
If the user were to change their clock in the middle of the day, this approach would reflect that change. While it requires slightly more resources, it should be negligible.
I tried the "pause" pacakage. It does not work for Python 3.x. From the pause package I extracted the code required to wait until a specific datetime and made the following def.
def wait_until(execute_it_now):
while True:
diff = (execute_it_now - datetime.now()).total_seconds()
if diff <= 0:
return
elif diff <= 0.1:
time.sleep(0.001)
elif diff <= 0.5:
time.sleep(0.01)
elif diff <= 1.5:
time.sleep(0.1)
else:
time.sleep(1)
adapt this:
from datetime import datetime, timedelta
from time import sleep
now = datetime.utcnow
to = (now() + timedelta(days = 1)).replace(hour=1, minute=0, second=0)
sleep((to-now()).seconds)
Slightly beside the point of the original question:
Even if you don't want to muck around with crontabs, if you can schedule python scripts to those hosts, you might be interested to schedule anacron tasks? anacron's major differentiator to cron is that it does not rely the computer to run continuously. Depending on system configuration you may need admin rights even for such user-scheduled tasks.
A similar, more modern tool is upstart provided by the Ubuntu folks: http://upstart.ubuntu.com/
This does not yet even have the required features. But scheduling jobs and replacing anacron is a planned feature. It has quite some traction due to its usage as Ubuntu default initd replacement. (I am not affiliated with the project)
Of course, with the already provided answer, you can code the same functionality into your python script and it might suit you better in your case.
Still, for others, anacron or similar existing systems might be a better solution. anacron is preinstalled on many current linux distributions (there are portability issues for windows users).
Wikipedia provides a pointer page: https://en.wikipedia.org/wiki/Anacron
If you do go for a python version I'd look at the asynchronous aspect, and ensure the script works even if the time is changed (daylight savings, etc) as others have commented already. Instead of waiting til a pre-calculated future, I'd always at maximum wait one hour, then re-check the time. The compute cycles invested should be negligible even on mobile, embedded systems.
Asynchronous version of Omrii's solution
import datetime
import asyncio
async def sleep_until(hour: int, minute: int, second: int):
"""Asynchronous wait until specific hour, minute and second
Args:
hour (int): Hour
minute (int): Minute
second (int): Second
"""
t = datetime.datetime.today()
future = datetime.datetime(t.year, t.month, t.day, hour, minute, second)
if t.timestamp() > future.timestamp():
future += datetime.timedelta(days=1)
await asyncio.sleep((future - t).total_seconds())
I know is way late for this, but I wanted to post an answer (inspired on the marked answer) considering systems that might have - incorrect - desired timezone + include how to do this threaded for people wondering how.
It looks big because I'm commenting every step to explain the logic.
import pytz #timezone lib
import datetime
import time
from threading import Thread
# using this as I am, check list of timezone strings at:
## https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
TIMEZONE = pytz.timezone("America/Sao_Paulo")
# function to return desired seconds, even if it's the next day
## check the bkp_time variable (I use this for a bkp thread)
## to edit what time you want to execute your thread
def get_waiting_time_till_two(TIMEZONE):
# get current time and date as our timezone
## later we remove the timezone info just to be sure no errors
now = datetime.datetime.now(tz=TIMEZONE).replace(tzinfo=None)
curr_time = now.time()
curr_date = now.date()
# Make 23h30 string into datetime, adding the same date as current time above
bkp_time = datetime.datetime.strptime("02:00:00","%H:%M:%S").time()
bkp_datetime = datetime.datetime.combine(curr_date, bkp_time)
# extract the difference from both dates and a day in seconds
bkp_minus_curr_seconds = (bkp_datetime - now).total_seconds()
a_day_in_seconds = 60 * 60 * 24
# if the difference is a negative value, we will subtract (- with + = -)
# it from a day in seconds, otherwise it's just the difference
# this means that if the time is the next day, it will adjust accordingly
wait_time = a_day_in_seconds + bkp_minus_curr_seconds if bkp_minus_curr_seconds < 0 else bkp_minus_curr_seconds
return wait_time
# Here will be the function we will call at threading
def function_we_will_thread():
# this will make it infinite during the threading
while True:
seconds = get_waiting_time_till_two(TIMEZONE)
time.sleep(seconds)
# Do your routine
# Now this is the part where it will be threading
thread_auto_update = Thread(target=function_we_will_thread)
thread_auto_update.start()
It takes only one of the very basic libraries.
import time
sleep_until = 'Mon Dec 25 06:00:00 2020' # String format might be locale dependent.
print("Sleeping until {}...".format(sleep_until))
time.sleep(time.mktime(time.strptime(sleep_until)) - time.time())
time.strptime() parses the time from string -> struct_time tuple. The string can be in different format, if you give strptime() parse-format string as a second argument. E.g.
time.strptime("12/25/2020 02:00AM", "%m/%d/%Y %I:%M%p")
time.mktime() turns the struct_time -> epoch time in seconds.
time.time() gives current epoch time in seconds.
Substract the latter from the former and you get the wanted sleep time in seconds.
sleep() the amount.
If you just want to sleep until whatever happens to be the next 2AM, (might be today or tomorrow), you need an if-statement to check if the time has already passed today. And if it has, set the wake up for the next day instead.
import time
sleep_until = "02:00AM" # Sets the time to sleep until.
sleep_until = time.strftime("%m/%d/%Y " + sleep_until, time.localtime()) # Adds todays date to the string sleep_until.
now_epoch = time.time() #Current time in seconds from the epoch time.
alarm_epoch = time.mktime(time.strptime(sleep_until, "%m/%d/%Y %I:%M%p")) # Sleep_until time in seconds from the epoch time.
if now_epoch > alarm_epoch: #If we are already past the alarm time today.
alarm_epoch = alarm_epoch + 86400 # Adds a day worth of seconds to the alarm_epoch, hence setting it to next day instead.
time.sleep(alarm_epoch - now_epoch) # Sleeps until the next time the time is the set time, whether it's today or tomorrow.
What about this handy and simple solution?
from datetime import datetime
import time
pause_until = datetime.fromisoformat('2023-02-11T00:02:00') # or whatever timestamp you gonna need
time.sleep((pause_until - datetime.now()).total_seconds())
from datetime import datetime
import time, operator
time.sleep([i[0]*3600 + i[1]*60 for i in [[H, M]]][0] - [i[0]*3600 + i[1]*60 for i in [map(int, datetime.now().strftime("%H:%M").split(':'))]][0])
Instead of using the wait() function, you can use a while-loop checking if the specified date has been reached yet:
if datetime.datetime.utcnow() > next_friday_10am:
# run thread or whatever action
next_friday_10am = next_friday_10am()
time.sleep(30)
def next_friday_10am():
for i in range(7):
for j in range(24):
for k in range(60):
if (datetime.datetime.utcnow() + datetime.timedelta(days=i)).weekday() == 4:
if (datetime.datetime.utcnow() + datetime.timedelta(days=i, hours=j)).hour == 8:
if (datetime.datetime.utcnow() + datetime.timedelta(days=i, hours=j, minutes=k)).minute == 0:
return datetime.datetime.utcnow() + datetime.timedelta(days=i, hours=j, minutes=k)
Still has the time-checking thread check the condition every after 30 seconds so there is more computing required than in waiting, but it's a way to make it work.