views:

92

answers:

3

dear all,

As a matter of general interest I'm wondering if there's a more elegant/efficient way to do this. I have a function that compares two start/end tuples of dates returning true if they intersect.

from datetime import date
def date_intersection(t1, t2):
    t1start, t1end = t1[0], t1[1]
    t2start, t2end = t2[0], t2[1]

    if t1end < t2start: return False
    if t1end == t2start: return True
    if t1start == t2start: return True
    if t1start < t2start and t2start < t1end: return True
    if t1start > t2start and t1end < t2end: return True
    if t1start < t2start and t1end > t2end: return True
    if t1start < t2end and t1end > t2end: return True
    if t1start > t2start and t1start < t2end: return True
    if t1start == t2end: return True
    if t1end == t2end: return True 
    if t1start > t2end: return False

so if:

d1 = date(2000, 1, 10)
d2 = date(2000, 1, 11)
d3 = date(2000, 1, 12)
d4 = date(2000, 1, 13)

then:

>>> date_intersection((d1,d2),(d3,d4))
False
>>> date_intersection((d1,d2),(d2,d3))
True
>>> date_intersection((d1,d3),(d2,d4))
True

etc.

I'm curious to know if there's a more pythonic/elegant/more efficient/less verbose/generally better, way to do this with maybe mxDateTime or some clever hack with timedelta or set()?

An alternative and useful form would be for the function to return a start/end tuple of the intersection if one is found

Thanks

A: 
if t1end < t2start or t1start > t2end: return False
if t1start <= t2end or t2start <= t1start: return True
return False

Won't that cover all intersecting sets?

Nathon
Well, your code simplifies to return t1end >= t2start and t1start <= t2end
Amoss
ah, right...1 more
Nathon
+5  A: 

It's not really more Pythonic, but you can simply the logic to decide on an intersection somewhat. This particular problems crops up a lot:

return (t1start <= t2start and t2start <= t1end) or \
       (t2start <= t1start and t1start <= t2end)

To see why this works think about the different possible ways that the two intervals can intersect and see that the starting point of one must always be within the range of the other.

Amoss
yes! very nice. It still makes me go a little cross-eyed, but you've collapsed my exhaustive case analysis into a very clean expression. Thanks a lot, this helps clarify my thinking.
jjon
+1  A: 

Here's a version that give you the range of intersection. IMHO, it might not be the most optimize # of conditions, but it clearly shows when t2 overlaps with t1. You can modify based on other answers if you just want the true/false.

if (t1start <= t2start <= t2end <= t1end):
    return t2start,t2end
elif (t1start <= t2start <= t1end):
    return t2start,t1end
elif (t1start <= t2end <= t1end):
    return t1start,t2end
elif (t2start <= t1start <= t1end <= t2end):
    return t1start,t1end
else:
    return None
fseto
FYI... chaining comparison operators: http://stackoverflow.com/questions/101268/hidden-features-of-python/101945#101945
fseto
Thanks much for the link to chaining operators, that's very helpful.
jjon