def validate_timeprecision(value, name): if self.precision == "day": if floor_datetime_to_midnight(value) != value: raise ValueError( "%s time value %s has higher precision than set precision %s" % (name, value, self.precision)) if value.tzinfo is not None: raise ValueError( "all-day timespan %s time %s can't have a timezone" % (name, value))
def on(self, instant: DatetimeLike, strict: bool = False) -> Iterator[Event]: """ Iterates (in chronological order) over all events that occurs on `day`. :param strict: if True events will be returned only if they are strictly *included* in `day` """ begin = floor_datetime_to_midnight(ensure_datetime(instant)) end = ceil_datetime_to_midnight( ensure_datetime(instant) + timedelta(seconds=1)) query = self.__normalize_timespan(begin, end) if strict: return self.included(query) else: return self.overlapping(query)
def make_all_day(self) -> "Timespan": if self.is_all_day(): return self # Do nothing if we already are a all day timespan begin = self.begin_time if begin is not None: begin = floor_datetime_to_midnight(begin).replace(tzinfo=None) end = self.get_effective_end() if end is not None: end = ceil_datetime_to_midnight(end).replace(tzinfo=None) if end == begin: # we also add another day if the duration would be 0 otherwise end = end + TIMEDELTA_DAY if self.get_end_representation() == "duration": assert end is not None assert begin is not None return self.replace(begin, None, end - begin, "day") else: return self.replace(begin, end, None, "day")
def assert_make_all_day_valid(self, ts_secs: EventTimespan, ts_days: EventTimespan): # check resolution for all_day assert ts_days.get_effective_duration() % td(days=1) == td(0) assert floor_datetime_to_midnight( ts_days.get_begin()) == ts_days.get_begin() assert floor_datetime_to_midnight( ts_days.get_effective_end()) == ts_days.get_effective_end() # minimum duration is 0s / 1d assert ts_secs.get_effective_duration() >= td() assert ts_days.get_effective_duration() >= td(days=1) # test inclusion and boundaries ts_days_begin_wtz = ts_days.get_begin().replace( tzinfo=ts_secs.get_begin().tzinfo) ts_days_eff_end_wtz = ts_days.get_effective_end().replace( tzinfo=ts_secs.get_effective_end().tzinfo) assert ts_days_begin_wtz <= ts_secs.get_begin() assert ts_days_eff_end_wtz >= ts_secs.get_effective_end() assert ts_days.get_effective_duration( ) >= ts_secs.get_effective_duration() # test that we didn't decrease anything begin_earlier = ts_secs.get_begin() - ts_days_begin_wtz end_later = ts_days_eff_end_wtz - ts_secs.get_effective_end() duration_bigger = ts_days.get_effective_duration( ) - ts_secs.get_effective_duration() assert begin_earlier >= td() assert end_later >= td() assert duration_bigger >= td() # test that we didn't drift too far assert begin_earlier < td(hours=24) instant_to_one_day = (ts_secs.get_begin().hour == 0 and ts_secs.get_effective_duration() == td()) if instant_to_one_day: assert end_later == td(hours=24) else: assert end_later < td(hours=24) # NOTICE: duration might grow by 48h, not only 24, as we floor the begin time (which might be 23:59) # and ceil the end time (which might be 00:01) assert duration_bigger < td(hours=24 * 2) # test that we made no unnecessary modification if ts_secs.get_begin() == floor_datetime_to_midnight( ts_secs.get_begin()): assert ts_days.get_begin() == ts_secs.get_begin().replace( tzinfo=None) if ts_secs.get_effective_end() == floor_datetime_to_midnight( ts_secs.get_effective_end()): if instant_to_one_day: # here we need to convert duration=0 to duration=1d assert ts_days.get_effective_end( ) == ts_secs.get_effective_end().replace(tzinfo=None) + td( days=1) else: assert ts_days.get_effective_end( ) == ts_secs.get_effective_end().replace(tzinfo=None) # the following won't hold for events that don't start at 00:00, compare NOTICE above if ts_secs.get_begin().hour == 0: if instant_to_one_day: # here we need to convert duration=0 to duration=1d assert duration_bigger == td(hours=24) else: # if we start at midnight, only the end time is ceiled, which can only add up to 24h instead of 48h assert duration_bigger < td(hours=24) mod_duration = (ts_secs.get_effective_duration() % td(days=1)) if ts_secs.get_effective_duration() <= td(days=1): # here we need to convert duration<1d to duration=1d assert ts_days.get_effective_duration() == td(days=1) elif mod_duration == td(): assert ts_days.get_effective_duration( ) == ts_secs.get_effective_duration() else: assert ts_days.get_effective_duration( ) == ts_secs.get_effective_duration() + td( days=1) - mod_duration # log data if self.data is not None: self.data.append(( str(ts_secs), ts_secs.get_effective_duration().days * 24 + ts_secs.get_effective_duration().seconds / 3600, str(ts_days), ts_days.get_effective_duration().days * 24 + ts_days.get_effective_duration().seconds / 3600, begin_earlier, end_later, duration_bigger, ))