Python - 判断当前时间是否在两个时间之间

13

我正在尝试找到最干净/最Pythonic的方法来评估“现在”是否在两个时间之间;但是,开始/结束时间可能跨越一天边界,也可能不跨越-例如(只是使用简单的例子):

onhour=23
onmin=30
offhour=4
offmin=15
timenow = datetime.datetime.now().time()

对于这个问题,简单的 if START < NOW < END 场景不适用!

我目前拥有一些代码,用于判断当前是否为“夜间”,它看起来像这样:

def check_time(timenow, onhour, onmin, offhour, offmin, verbose):
    now = datetime.datetime.now()
    now_time = now.time()
    # If we're actually scheduling at night:
    if int(offhour) < int(onhour):
        # Check to see if we're in daylight times (ie. off schedule)
        if datetime.time(int(offhour),int(offmin)) <= now_time <= datetime.time(int(onhour),int(onmin)):
            if verbose == True:
                print("Day Time detected.")
            return False
        else:
            if verbose == True:
                print("Night Time detected.")
            return True
    else:
        if datetime.time(int(onhour),int(onmin)) <= now_time <= datetime.time(int(offhour),int(offmin)):
            if verbose == True:
                print("Night Time detected.")
            return True
        else:
            if verbose == True:
                print("Day Time detected.")
            return False

如果标题看起来不像是什么新鲜事,我表示歉意,但是在回顾了一些类似问题的现有答案后,例如:

我注意到这些答案似乎没有考虑开始和结束时间跨越一天边界的情况。

除此之外,任何关于基于日期的计划的想法也会非常有用!例如,“从周一到周五,在23:00打开,在04:00关闭”——但要管理前后两天的开关(否则,某些设备可能在周五打开,但在周六未关闭,然后包括周六意味着它又会在23:00重新打开!...)

我考虑过简单地“在X点打开,睡眠Y秒”来解决这个问题...但如果脚本在“开启”周期内启动,则要等到下一次运行才会启动... 但这似乎是最简单的选择! :)

我希望有一些很棒的模块可以完成所有这些... :D

对我来说,Python2.7-3.2的兼容性也非常重要!


你如何知道ontime和offtime指的是哪一天?例如,如果“现在”是12月11日,你如何确定在你的示例中间隔是从12月10日23:30到12月11日4:15还是从12月11日23:30到12月12日4:15? - leeladam
3
问题似乎在于你只有小时和分钟,没有日期。如果你有三个日期,那么 date1 <= date2 <= date3 就可以正常工作。 - Simeon Visser
你有没有了解过高级Python调度器 - jonrsharpe
首先,为您想要的所有变化编写测试用例... - John La Rooy
@SimeonVisser - 我同意,肯定有改进的空间;但我无法理解如何评估offhour应该分配给今天还是明天...我猜测评估time.now()是否大于offhour或类似的方法可能已经足够了... - dalgibbard
@jonrsharpe - 我快速查看了高级Python调度程序,它似乎很适合启动工作,但我没有看到太多关于基于日期/时间定义“停止”的内容(只有一个“持续时间”等效物)?也许我错过了文档中的示例? - dalgibbard
4个回答

23

判断给定时间(没有日期)是否在给定的开始和结束时间之间(不包括结束时间):

def in_between(now, start, end):
    if start <= end:
        return start <= now < end
    else: # over midnight e.g., 23:30-04:15
        return start <= now or now < end

示例:

from datetime import datetime, time

print("night" if in_between(datetime.now().time(), time(23), time(4)) else "day")

如果开始时间是凌晨2点,结束时间也是凌晨2点,而现在的时间是凌晨4点,那么这样不会失败吗?第一个if语句应该是读作“如果开始时间小于结束时间”吧? - rouble
@rouble [2AM, 2AM)是一个空范围(正如答案中明确指出的那样,“不包括末尾”)。也就是说,代码的行为符合文档说明。如果需要,要求和代码都可以更改。但是,在许多情况下,指定没有右边界的范围有益(这就是为什么在Python中range(2,2)也是空的原因)。 - jfs
我理解你的观点。你的答案是更好的答案(因此得到了赞)。我认为,当我们试图确定一个时间是否在一天的时间段内时,应该允许完整的24小时时间范围。 - rouble

8

你的代码有点混乱。我会像这样做:

import datetime

DAY, NIGHT = 1, 2
def check_time(time_to_check, on_time, off_time):
    if on_time > off_time:
        if time_to_check > on_time or time_to_check < off_time:
            return NIGHT, True
    elif on_time < off_time:
        if time_to_check > on_time and time_to_check < off_time:
            return DAY, True
    elif time_to_check == on_time:
        return None, True
    return None, False


on_time = datetime.time(23,30)
off_time = datetime.time(4,15)
timenow = datetime.datetime.now().time()
current_time = datetime.datetime.now().time()

when, matching = check_time(current_time, on_time, off_time)

if matching:
    if when == NIGHT:
        print("Night Time detected.")
    elif when == DAY:
        print("Day Time detected.")

使用">="替换"if time_to_check"语句,这样是否可以简化代码,从而省去最后一个"elif"的需要? - dalgibbard
最后一个elif是用来处理on_time和off_time恰好相同(且time_to_check在此“间隔”中)的情况。在这种情况下,除非您根据感兴趣地区的日出/日落时间选择一些固定的“夜间”和“白天”间隔,否则无法确定它是“夜间”还是“白天”间隔。 - smeso

3
def is_hour_between(start, end, now):
    is_between = False

    is_between |= start <= now <= end
    is_between |= end < start and (start <= now or now <= end)

    return is_between

测试如下:

assert is_hour_between(6, 10, 6)
assert not is_hour_between(6, 10, 4)
assert is_hour_between(17, 20, 17)
assert not is_hour_between(17, 20, 16)

1

Kevron的帖子实际上帮助解决了我的问题。我的需求略有不同,我正在传递字符串。我的版本看起来像这样:

def is_hour_between(start, end):
    # Time Now
    now = datetime.datetime.now().time()
    # Format the datetime string
    time_format = '%Y-%m-%d %H:%M:%S'
    # Convert the start and end datetime to just time
    start = datetime.datetime.strptime(start, time_format).time()
    end = datetime.datetime.strptime(end, time_format).time()

    is_between = False
    is_between |= start <= now <= end
    is_between |= end <= start and (start <= now or now <= end)

    return is_between

check = is_hour_between('2021-04-07 08:30:00', '2021-04-07 04:29:00') #spans to the next day
print("time check", check) # result = True

希望这能帮助到在字符串时间方面有困难的人。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接