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 contains( self, a_datetime ): """Return True iff the interval includes the microsecond represented by a_datetime Raises a ValueError when a_datetime is in the future and is_ongoing is true. """ if LocalTimezone.in_future(a_datetime): raise ValueError( "It is unknown whether the ongoing interval {} contains " "the datetime object {} because it is in the future." .format(str(self), str(a_datetime)) ) return self.first <= a_datetime
def __new__(cls, first): """Set the cooresponding members to the provided values (See class docstring for member description) """ if first is None: raise ValueError("The starting time of a fogbugz " "OngoingTimeInterval must be defined.") if tzutil.is_naive(first): raise ValueError("Starting time of a fogbugz " "OngoingTimeInterval must be timezone aware") if LocalTimezone.in_future(first): raise ValueError( "The starting time of a fogbugz OngoingTimeInterval must not " "be in the future. ({})".format(str(first))) return cls.__bases__[0].__new__(cls, copy.copy(first))
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)