我知道我可以让线程在特定时间内睡眠:
time.sleep(NUM)
如何让线程睡到凌晨2点?我必须做数学来确定直到凌晨2点的秒数吗?或者是否有一些库函数?
(是的,我知道Windows中的cron和等效系统,但我想在python中正确地睡觉我的线程而不依赖于外部激励或处理信号。)
答案 0 :(得分:37)
这是一个半分辨率解决方案,不考虑时钟抖动或时钟调整。请参阅评论以了解如何摆脱它。
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).seconds)
# do 2AM stuff
答案 1 :(得分:20)
import pause
from datetime import datetime
pause.until(datetime(2015, 8, 12, 2))
答案 2 :(得分:5)
一种可能的方法是睡一个小时。每小时一次,检查时间是否在半夜。如果是,请继续操作。如果没有,请再睡一小时并继续。
如果用户在一天中间改变他们的时钟,这种方法将反映出这种变化。虽然它需要稍多的资源,但它应该可以忽略不计。
答案 3 :(得分:3)
我试过"暂停" pacakage。它不适用于Python 3.x.从暂停包中我提取了等待特定日期时间所需的代码并进行了以下定义。
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)
答案 4 :(得分:2)
稍微偏离原始问题:
即使您不想使用crontabs,如果您可以将python脚本安排到这些主机,您可能有兴趣安排anacron任务? anacron与cron的主要区别在于它不依赖于计算机连续运行。根据系统配置,即使对于此类用户计划任务,您也可能需要管理员权限。
类似的,更现代的工具是Ubuntu人员提供的新贵:http://upstart.ubuntu.com/ 这甚至还没有所需的功能。但是安排工作和更换anacron是一项计划的功能。由于其用作Ubuntu默认的initd替换,它具有相当大的吸引力。 (我不隶属于该项目)
当然,通过已经提供的答案,您可以在python脚本中编写相同的功能,在您的情况下它可能更适合您。
但是,对于其他人来说,anacron或类似的现有系统可能是更好的解决方案。 anacron预装在许多当前的Linux发行版上(Windows用户存在可移植性问题)。
维基百科提供了一个指针页面:https://en.wikipedia.org/wiki/Anacron
如果您选择python版本,我会查看异步方面,并确保脚本能够正常工作,即使时间已经改变(夏令时等),因为其他人已经评论过了。而不是等待直到预先计算的未来,我总是等待一个小时,然后重新检查时间。即使在移动嵌入式系统上,投入的计算周期也应该可以忽略不计。
答案 5 :(得分:2)
稍微更通用的解决方案(基于 Ross Rogers'),以防您还想增加分钟数。
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())
答案 6 :(得分:1)
适应此:
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)
答案 7 :(得分:0)
使用sleep
的另一种方法是对数减少超时。
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
以@MZA的答案和@Mads Y的评论为基础
答案 8 :(得分:0)
您可以使用while循环检查是否已达到指定的日期,而不是使用wait()函数:
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)
仍然有时间检查线程每30秒检查一次条件,因此所需的计算量要比等待时多,但这是使其工作的一种方法。
答案 9 :(得分:0)
我知道现在已经太晚了,但是我想发布一个答案(灵感来自已标记的答案),考虑到可能具有-错误-所需时区+包括如何做到这一点的系统,以供人们思考。
它看起来很大,因为我在评论每一步以解释逻辑。
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()
答案 10 :(得分:0)
它只需要一个非常基本的库。
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("12/25/2020 02:00AM", "%m/%d/%Y %I:%M%p")
如果您只想睡觉直到下一个凌晨2点(可能是今天或明天),您就需要一个if语句来检查时间是否今天已经过去。如果有的话,请改用第二天的唤醒方式。
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.
答案 11 :(得分:-1)
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])