def subinterval_starting_at_or_after( self, a_datetime ): """Returns the intersection between this TimeInterval and the interval which includes the microsecond represented by a_datetime and all time after it. Raises a ValueError when a_datetime is in the future and is_ongoing is true. a_datetime - a timezone aware datetime object The new first instant will be the later of a_datetime and self.first """ # Note that this will raise the required ValueError if # a_datetime is in the future if not self.contains(a_datetime): return EmptyTimeInterval() # Since the split point is not in the future, we can make the # required ongoing interval by taking the union of the time # that has already occurred at or after the split point with # all future time. up_to_now = BoundedTimeInterval(self.first, LocalTimezone.now()) intersection_up_to_now = ( up_to_now.subinterval_starting_at_or_after(a_datetime)) return OngoingTimeInterval(intersection_up_to_now.first)
def intersection_with( self, a_TimeInterval ): """Returns an interval representing the times that are in both this interval and a_TimeInterval Note: this is fragile and depends on knowing what all the subclasses of TimeInterval are (see my note on this method in the TimeInterval docstring) Raises a ValueError when this time interval contains instants in the future and a_TimeInterval is ongoing (since you don't know when the ongoing interval will stop.) """ # Detect if someone has implemented a subclass not known at # the time of this writing and tried to find the # intersection. Fail so this will be caught in testing. assert(isinstance( a_TimeInterval, (EmptyTimeInterval, BoundedTimeInterval, OngoingTimeInterval))) if a_TimeInterval.is_ongoing(): if LocalTimezone.in_future(self.last): raise ValueError( "Cannot determine the intersection between {} and {} " "because the first includes the future and the second is " "ongoing, so we don't know when it will stop.".format( self, a_TimeInterval)) else: # Here I assume that all objects with is_ongoing true # have a first member return (intersection_with( self, BoundedTimeInterval( a_TimeInterval.first, LocalTimezone.now() ))) elif hasattr(a_TimeInterval, 'first'): #Assume BoundedTimeInterval if ( # The two intervals overlap a_TimeInterval.first <= self.last and self.first <= a_TimeInterval.last): return BoundedTimeInterval( max(self.first, a_TimeInterval.first), min(self.last, a_TimeInterval.last)) else: return EmptyTimeInterval() else: # We can assume EmptyTimeInterval due to the assert at the # beginning of the method return EmptyTimeInterval()
def subinterval_before(self, a_datetime): """Returns the intersection between this TimeInterval and the interval containing all time up to but not including the microsecond represented by a_datetime Raises a ValueError when a_datetime is in the future and is_ongoing is true. Thus cannot return a TimeInterval object that is ongoing. a_datetime - a timezone aware datetime object """ # Note that this will raise the required ValueError if # a_datetime is in the future if not self.contains(a_datetime): return EmptyTimeInterval() # If the split point is not in the future, the time in this # interval before a_datetime is just the time before # a_datetime in the bounded subinterval of this ongoing # interval that measures the time that has already occurred up_to_now = BoundedTimeInterval(self.first, LocalTimezone.now()) return up_to_now.subinterval_before(a_datetime)