Set type for datetime intervals

Nagy László Zsolt gandalf at shopzeus.com
Mon Apr 4 06:15:19 EDT 2016


>> element ::= (start_point_in_time, end_point_in_time)
>> intervalset ::= { element1, element2, .... }
>>
>> Operations on elements:
>
> Eh... I think these should be realized as operations on an intervalset
> with a single element, and that elements should simply have properties
> like the start, end, and if it's open or closed on each side. In
> particular, any one of these could return something that is not an
> element.
The way it is implemented now:

* Intersection of two intervals will always be a single interval. It is
easy to see why.
* Union of two intervals is possible only for overlapping and touching
intervals.
* These operations are also defined on intervals sets, but they work in
all cases (empty sets and sets with various elements).

The reason of introducing the intersection of two intervals is to create
an easy way to tell if they have a non-empty intersection. So if i1 and
i2 are intervals, you can do this:

if i1*i2:
    pass # They share a common non-empty interval

If you define the intersection operation on interval sets only, then you
need to write something like this:

if IntervalSet(i1)*IntervalSet(i2):
    pass

which is both uglier and an overkill.

>
>> element1.intersect(element2)
> May return the empty set, if they do not intersect.
It does indeed.
>
>> element1.union(element2)
> May return {element1, element 2}
I choose to raise a ValueError if they don't overlap or touch. In order
to get the union of them in a set, you simply write:

IntervalSet(element1, element2)

which will unify them correctly.



>
>
>> Operations on sets:
>>
>> intervalset1.intersect(intervalset2)
>> intervalset1.union(intervalset2)
>> intervalset1.minus(intervalset2)
> These should be operators. s1 & s2, s1 | s2, s1 - s2. There's also a s1
> ^ s2 operation for python sets, the symmetric difference.

Well, I used +, *. Do you think that & and | would be better?
>
> Wouldn't it be useful to have some operations on datetimes?
>
> intervalset1.ltall(dt)
> .... all(dt < x.start or dt == x.start and x.startopen for x in dt)
> intervalset1.gtall(dt)
> .... all(dt > x.end or dt == x.end and x.endopen for x in dt)
> intervalset1.leall(dt)
> .... all(dt <= x.start for x in intervalset1) # I _think_ this is all
> you need for this
> intervalset1.geall(dt)
> .... all(dt >= x.end for x in intervalset1)
> dt in intervalset1
> ... any(dt in elem for x in intervalset1)
> dt in elem
> ... dt > elem.start and dt < elem.end or dt == elem.start and not
> elem.startopen or dt == elem.end and not elem.endopen
> min and max
> ... seems trivial, but what to return if the first/last element is open?
You are encouraged to add a pull request. Although I did not implement
open intervals, only closed ones. Here is my reasoning:

  * datetime instances have a fixed resolution, an open interval would
    be equal to a "one step less" closed interval.
  * There is a semantical problem when your try to define relations
    between open and closed intervals. Is an open interval less then a
    closed one? Is the difference of an equally sized open and closed
    interval empty or not? Does it evaluate to True of False?
  * Practical usage (at least in my project) these intervals measure
    something: working time of an employee, driving time of a car etc.
    From that point of view, there is no real difference between an open
    and a close interval. (I can see that there should be a difference
    for scientific applications.)

>
> I'm truly shocked you didn't even mention the "in" operation.
Me too. Simply I didn't need it yet. Added to TODO list. Just I need to
figure out if the "in" operator should return True when the element is
*partly* in the set. ;-)
>
> Also, as long as we're setting up an infinite (not really but anyway)
> set, why not also have the ability to have open-ended intervals that
> extend to infinity. Then you could invert the set too, for free given
> the minus operation: ~x == {(-inf, inf)} - x.
Great idea. The empty interval can be (-inf, -inf) which is smaller than
anything.
> It occurs to me that while I mentioned numbers, in principle you could
> use _any_ total-ordered type*. strings, tuples...
Yes, that is true. In fact the current class could be easily generalized
to support any ordered type. But then, how do we mix our own infinity
with math.inf?
> *nitpicker's corner: here, "type" is used to mean any set/class/category
> of objects, possibly of multiple python types and possibly not
> comprising the entirety of a single type, which are total-ordered with
> respect to each other, including the codomain of any key projection
> function suitable for sorting.




More information about the Python-list mailing list