【问题标题】:Test for overlapping times in Python在 Python 中测试重叠时间
【发布时间】:2019-11-29 18:14:05
【问题描述】:

我逐字逐句地关注这个,但与原始帖子相比得到了不同的结果,我不知道为什么。我想将成对的时间相互比较以检查它们重叠的位置。我正在使用 Python 3.6.6

Find if dates are overlapping in a list of N pairs

这是我编码的:

import datetime
from collections import namedtuple
from itertools import combinations

timesok = [('09:30', '10:00'), ('10:00', '10:30'), ('10:30', '11:00')]
wrongtimes1 = [('9:30', '10:00'), ('9:00', '10:30'), ('10:30', '11:00')]
wrongtimes2=[('9:30', '10:00'), ('10:00', '10:30'), ('9:15', '9:45')]

def test_overlap(dt1_st, dt1_end, dt2_st, dt2_end):

    Range = namedtuple('Range', ['start', 'end'])

    r1 = Range(start=dt1_st, end=dt1_end)
    r2 = Range(start=dt2_st, end=dt2_end)
    latest_start = max(r1.start, r2.start)
    earliest_end = min(r1.end, r2.end)
    overlap = (earliest_end - latest_start)
    return overlap.seconds

def find_overlaps(times):
    pairs = list(combinations(times, 2))
    print(pairs)
    for pair in pairs:
        start1 = datetime.datetime.strptime(pair[0][0], '%H:%M')
        end1   = datetime.datetime.strptime(pair[0][1], '%H:%M')
        start2 = datetime.datetime.strptime(pair[1][0], '%H:%M')
        end2   = datetime.datetime.strptime(pair[1][1], '%H:%M')
        yield test_overlap(start1, end1, start2, end2) > 0

list(find_overlaps(timesok))
list(find_overlaps(wrongtimes1))
list(find_overlaps(wrongtimes2))

 # timesok result:
list(find_overlaps(timesok))
[(('09:30', '10:00'), ('10:00', '10:30')), 
 (('09:30', '10:00'), ('10:30', '11:00')), 
 (('10:00', '10:30'), ('10:30', '11:00'))]
Out[7]: [False, True, False]

 # wrongtimes1 result:
list(find_overlaps(wrongtimes1))
[(('9:30', '10:00'), ('9:00', '10:30')), 
 (('9:30', '10:00'), ('10:30', '11:00')),
 (('9:00', '10:30'), ('10:30', '11:00'))]
Out[8]: [True, True, False]

 # wrongtimes2 result:
list(find_overlaps(wrongtimes2))
[(('9:30', '10:00'), ('10:00', '10:30')), 
 (('9:30', '10:00'), ('9:15', '9:45')), 
 (('10:00', '10:30'), ('9:15', '9:45'))]
Out[9]: [False, True, True]

我认为结果应该如下(与上面链接中的原始示例相对应):

Out[7]: [False, False, False]
Out[8]: [True, False, False]
Out[9]: [False, True, False]

我在这里遗漏了一些非常明显的东西吗?我是一个 Python 新手,所以对我温柔一点(!)

【问题讨论】:

    标签: python-3.x time


    【解决方案1】:

    overlap.seconds 不会返回您认为的结果。

    overlap 是datetime 减法的结果,即datetime.timedelta。

    timedelta.seconds 确实不返回总秒数。它返回增量的第二部分,如果 timedelta 是 -1 day, 23:45:00,timedelta.seconds 是 85500。

    你想写的是overlap.total_seconds():

    def test_overlap(dt1_st, dt1_end, dt2_st, dt2_end):
    
        Range = namedtuple('Range', ['start', 'end'])
    
        r1 = Range(start=dt1_st, end=dt1_end)
        r2 = Range(start=dt2_st, end=dt2_end)
        latest_start = max(r1.start, r2.start)
        earliest_end = min(r1.end, r2.end)
        overlap = (earliest_end - latest_start)
        return overlap.total_seconds()
    

    您仍然有一个问题,即您的时间都必须在同一天,并且不能跨越午夜。我不认为在这里使用datetime 是正确的方法,我认为编写自定义程序更容易。

    给你:

    from itertools import combinations
    
    def test_overlap(t1_st, t1_end, t2_st, t2_end):
    
        def convert_to_minutes(t_str):
            hours, minutes = t_str.split(':')
            return 60*int(hours)+int(minutes)
    
        t1_st = convert_to_minutes(t1_st)
        t1_end = convert_to_minutes(t1_end)
        t2_st = convert_to_minutes(t2_st)
        t2_end = convert_to_minutes(t2_end)
    
        # Check for wrapping time differences
        if t1_end < t1_st:
            if t2_end < t2_st:
                # Both wrap, therefore they overlap at midnight
                return True
            # t2 doesn't wrap. Therefore t1 has to start after t2 and end before
            return t1_st < t2_end or t2_st < t1_end
    
        if t2_end < t2_st:
            # only t2 wraps. Same as before, just reversed
            return t2_st < t1_end or t1_st < t2_end
    
        # They don't wrap and the start of one comes after the end of the other,
        # therefore they don't overlap
        if t1_st >= t2_end or t2_st >= t1_end:
            return False
    
        # In all other cases, they have to overlap
        return True
    
    times = [('09:30', '00:00'), ('07:00', '00:30'), ('10:30', '00:15'), ('12:15', '13:30'), ('10:00', '11:00'), ('00:15', '01:15')]
    
    pairs = list(combinations(times, 2))
    for pair in pairs:
        start1 = pair[0][0]
        end1   = pair[0][1]
        start2 = pair[1][0]
        end2   = pair[1][1]
        print(str(test_overlap(start1, end1, start2, end2)) + "\t" + str(pair))
    
    True    (('09:30', '00:00'), ('07:00', '00:30'))
    True    (('09:30', '00:00'), ('10:30', '00:15'))
    True    (('09:30', '00:00'), ('12:15', '13:30'))
    True    (('09:30', '00:00'), ('10:00', '11:00'))
    False   (('09:30', '00:00'), ('00:15', '01:15'))
    True    (('07:00', '00:30'), ('10:30', '00:15'))
    True    (('07:00', '00:30'), ('12:15', '13:30'))
    True    (('07:00', '00:30'), ('10:00', '11:00'))
    True    (('07:00', '00:30'), ('00:15', '01:15'))
    True    (('10:30', '00:15'), ('12:15', '13:30'))
    True    (('10:30', '00:15'), ('10:00', '11:00'))
    False   (('10:30', '00:15'), ('00:15', '01:15'))
    False   (('12:15', '13:30'), ('10:00', '11:00'))
    False   (('12:15', '13:30'), ('00:15', '01:15'))
    False   (('10:00', '11:00'), ('00:15', '01:15'))
    

    【讨论】:

    • 谢谢,这真的很有帮助。我真的把头发扯掉了!实际上,我的数据有这样的时间:times= [('09:30', '00:00'), ('07:00', '00:30'), ('10:30', '00:15'), ('12:15', '13:30', ('10:00', '11:00')] 所以前三个条目跨越一天以上。例如,我已经注意到上面的代码将为前 2 对返回 false。有没有办法克服这个。我试图避免在我的输入中使用日期,因为我正在查看固定的每日时间表(日期无关紧要)。
    • 实施了解决包装问题的自定义解决方案。希望这会有所帮助。
    猜你喜欢
    • 2020-02-28
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-08
    相关资源
    最近更新 更多