cardinal_pythonlib.interval¶
Original code copyright (C) 2009-2022 Rudolf Cardinal (rudolf@pobox.com).
This file is part of cardinal_pythonlib.
Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Time interval classes and related functions.
-
class
cardinal_pythonlib.interval.
Interval
(start: datetime.datetime, end: datetime.datetime)[source]¶ Object representing a time interval, with start and end objects that are normally
datetime.datetime
objects (though with care, a subset of some methods are possible withdatetime.date
objects; caveat emptor, and some methods will crash).Does not handle open-ended intervals (−∞, +∞) or null intervals.
There’s probably an existing class for this…
Creates the interval.
-
component_on_date
(date: datetime.date) → Optional[cardinal_pythonlib.interval.Interval][source]¶ Returns the part of this interval that falls on the date given, or
None
if the interval doesn’t have any part during that date.
-
contains
(time: datetime.datetime, inclusive: bool = True) → bool[source]¶ Does the interval contain a momentary time?
Parameters: - time – the
datetime.datetime
to check - inclusive – use inclusive rather than exclusive range checks?
- time – the
-
contiguous
(other: cardinal_pythonlib.interval.Interval) → bool[source]¶ Does this interval overlap or touch the other?
-
cut
(times: Union[datetime.datetime, List[datetime.datetime]]) → List[cardinal_pythonlib.interval.Interval][source]¶ Returns a list of intervals produced by using times (a list of
datetime.datetime
objects, or a single such object) as a set of knives to slice this interval.
-
day_night_duration
(daybreak: datetime.time = datetime.time(7, 0), nightfall: datetime.time = datetime.time(19, 0)) → Tuple[datetime.timedelta, datetime.timedelta][source]¶ Returns a
(day, night)
tuple ofdatetime.timedelta
objects giving the duration of this interval that falls into day and night respectively.
-
static
dayspan
(startdate: datetime.date, enddate: datetime.date, include_end: bool = True) → Optional[cardinal_pythonlib.interval.Interval][source]¶ Returns an
Interval
representing the date range given, from midnight at the start of the first day to midnight at the end of the last (i.e. at the start of the next day after the last), or if include_end is False, 24h before that.If the parameters are invalid, returns
None
.
-
static
daytime
(date: datetime.date, daybreak: datetime.time = datetime.time(7, 0), nightfall: datetime.time = datetime.time(19, 0)) → cardinal_pythonlib.interval.Interval[source]¶ Returns an
Interval
representing daytime on the date given.
-
duration
() → datetime.timedelta[source]¶ Returns a datetime.timedelta object representing the duration of this interval.
-
duration_in
(units: str) → float[source]¶ Returns the duration of this interval in the specified units, as per
convert_duration()
.
-
duration_outside_uk_normal_working_hours
(starttime: datetime.time = datetime.time(7, 0), endtime: datetime.time = datetime.time(19, 0), weekdays_only: bool = False, weekends_only: bool = False) → datetime.timedelta[source]¶ Returns a duration (a
datetime.timedelta
object) representing the number of hours outside normal working hours.This is not simply a subset of
day_night_duration()
, because weekends are treated differently (they are always out of hours).The options allow the calculation of components on weekdays or weekends only.
-
intersection
(other: cardinal_pythonlib.interval.Interval) → Optional[cardinal_pythonlib.interval.Interval][source]¶ Returns an
Interval
representing the intersection of this and theother
, orNone
if they don’t overlap.
-
n_weekends
() → int[source]¶ Returns the number of weekends that this interval covers. Includes partial weekends.
-
overlaps
(other: cardinal_pythonlib.interval.Interval) → bool[source]¶ Does this interval overlap the other?
Overlap:
S--------S S---S S---S O---O O---O O---O
Simpler method of testing is for non-overlap!
S---S S---S O---O O---O
-
saturdays_of_weekends
() → Set[datetime.date][source]¶ Returns the dates of all Saturdays that are part of weekends that this interval covers (each Saturday representing a unique identifier for that weekend). The Saturday itself isn’t necessarily the part of the weekend that the interval covers!
-
union
(other: cardinal_pythonlib.interval.Interval) → cardinal_pythonlib.interval.Interval[source]¶ Returns an interval spanning the extent of this and the
other
.
-
-
class
cardinal_pythonlib.interval.
IntervalList
(intervals: List[cardinal_pythonlib.interval.Interval] = None, no_overlap: bool = True, no_contiguous: bool = True)[source]¶ Object representing a list of Intervals. Maintains an internally sorted state (by interval start time).
Creates the
IntervalList
.Parameters: - intervals – optional list of
Interval
objects to incorporate into theIntervalList
- no_overlap – merge intervals that overlap (now and on subsequent addition)?
- no_contiguous – if
no_overlap
is set, merge intervals that are contiguous too?
-
add
(interval: cardinal_pythonlib.interval.Interval) → None[source]¶ Adds an interval to the list. If
self.no_overlap
is True, as is the default, it will merge any overlapping intervals thus created.
-
copy
(no_overlap: bool = None, no_contiguous: bool = None) → cardinal_pythonlib.interval.IntervalList[source]¶ Makes and returns a copy of the
IntervalList
. Theno_overlap
/no_contiguous
parameters can be changed.Parameters: - no_overlap – merge intervals that overlap (now and on subsequent addition)?
- no_contiguous – if
no_overlap
is set, merge intervals that are contiguous too?
-
cumulative_before_during_after
(start: datetime.datetime, when: datetime.datetime) → Tuple[datetime.timedelta, datetime.timedelta, datetime.timedelta][source]¶ For a given time,
when
, returns the cumulative time- after
start
but beforeself
begins, prior towhen
; - after
start
and during intervals represented byself
, prior towhen
; - after
start
and after at least one interval represented byself
has finished, and not within any intervals represented byself
, and prior towhen
.
Parameters: - start – the start time of interest (e.g. before
self
begins) - when – the time of interest
Returns: before, during, after
Return type: tuple
Illustration
start: S self: X---X X---X X---X X---X when: W before: ---- during: ----- ----- ----- after: ------- ------- ----
- after
-
cumulative_gaps_to
(when: datetime.datetime) → datetime.timedelta[source]¶ Return the cumulative time within our gaps, up to
when
.
-
cumulative_time_to
(when: datetime.datetime) → datetime.timedelta[source]¶ Returns the cumulative time contained in our intervals up to the specified time point.
-
duration_outside_nwh
(starttime: datetime.time = datetime.time(7, 0), endtime: datetime.time = datetime.time(19, 0)) → datetime.timedelta[source]¶ Returns the total duration outside normal working hours, i.e. evenings/nights, weekends (and Bank Holidays).
-
durations
() → List[datetime.timedelta][source]¶ Returns a list of
datetime.timedelta
objects representing the durations of each interval in our list.
-
end_date
() → Optional[datetime.date][source]¶ Returns the end date of the set of intervals, or
None
if empty.
-
end_datetime
() → Optional[datetime.datetime][source]¶ Returns the end date of the set of intervals, or
None
if empty.
-
extent
() → Optional[cardinal_pythonlib.interval.Interval][source]¶ Returns an
Interval
running from the earliest start of an interval in this list to the latest end. ReturnsNone
if we are empty.
-
first_interval_ending
(end: datetime.datetime) → Optional[cardinal_pythonlib.interval.Interval][source]¶ Returns our first interval that ends with the
end
parameter, orNone
.
-
first_interval_starting
(start: datetime.datetime) → Optional[cardinal_pythonlib.interval.Interval][source]¶ Returns our first interval that starts with the
start
parameter, orNone
.
-
gap_subset
(interval: cardinal_pythonlib.interval.Interval, flexibility: int = 2) → cardinal_pythonlib.interval.IntervalList[source]¶ Returns an IntervalList that’s a subset of this one, only containing gaps between intervals that meet the interval criterion.
See
subset()
for the meaning of parameters.
-
gaps
() → cardinal_pythonlib.interval.IntervalList[source]¶ Returns all the gaps between intervals, as an
IntervalList
.
-
get_overlaps
() → cardinal_pythonlib.interval.IntervalList[source]¶ Returns an
IntervalList
containing intervals representing periods of overlap between intervals in this one.
-
list
() → List[cardinal_pythonlib.interval.Interval][source]¶ Returns the contained list of
Interval
objects.
-
longest_duration
() → Optional[datetime.timedelta][source]¶ Returns the duration of the longest interval, or None if none.
-
longest_interval
() → Optional[cardinal_pythonlib.interval.Interval][source]¶ Returns the longest interval, or
None
if none.
-
max_consecutive_days
() → Optional[Tuple[int, cardinal_pythonlib.interval.Interval]][source]¶ The length of the longest sequence of days in which all days include an interval.
Returns: (longest_length, longest_interval)
wherelongest_interval
is aInterval
containing the start and end date of the longest span – orNone
if we contain no intervals.Return type: tuple
-
n_weekends
() → int[source]¶ Returns the number of weekends that the intervals collectively touch (where “touching a weekend” means “including time on a Saturday or a Sunday”).
-
remove_overlap
(also_remove_contiguous: bool = False) → None[source]¶ Merges any overlapping intervals.
Parameters: also_remove_contiguous – treat contiguous (as well as overlapping) intervals as worthy of merging?
-
shortest_duration
() → Optional[datetime.timedelta][source]¶ Returns the duration of the longest interval, or
None
if none.
-
shortest_gap
() → Optional[cardinal_pythonlib.interval.Interval][source]¶ Find the shortest gap between intervals, or
None
if none.
-
shortest_gap_duration
() → Optional[datetime.timedelta][source]¶ Find the duration of the shortest gap between intervals, or
None
if none.
-
shortest_interval
() → Optional[cardinal_pythonlib.interval.Interval][source]¶ Returns the shortest interval, or
None
if none.
-
start_date
() → Optional[datetime.date][source]¶ Returns the start date of the set of intervals, or
None
if empty.
-
start_datetime
() → Optional[datetime.datetime][source]¶ Returns the start date of the set of intervals, or
None
if empty.
-
subset
(interval: cardinal_pythonlib.interval.Interval, flexibility: int = 2) → cardinal_pythonlib.interval.IntervalList[source]¶ Returns an IntervalList that’s a subset of this one, only containing intervals that meet the “interval” parameter criterion. What “meet” means is defined by the
flexibility
parameter.flexibility == 0
: permits only wholly contained intervals:interval: I----------------I intervals in self that will/won't be returned: N---N N---N Y---Y N---N N---N N---N N---N
flexibility == 1
: permits overlapping intervals as well:I----------------I N---N Y---Y Y---Y Y---Y N---N N---N N---N
flexibility == 2
: permits adjoining intervals as well:I----------------I N---N Y---Y Y---Y Y---Y N---N Y---Y Y---Y
-
sufficient_gaps
(every_n_days: int, requiredgaps: List[datetime.timedelta], flexibility: int = 2) → Tuple[bool, Optional[cardinal_pythonlib.interval.Interval]][source]¶ Are gaps present sufficiently often? For example:
every_n_days=21 requiredgaps=[ datetime.timedelta(hours=62), datetime.timedelta(hours=48), ]
… means “is there at least one 62-hour gap and one (separate) 48-hour gap in every possible 21-day sequence within the IntervalList?
- If
flexibility == 0
: gaps must be WHOLLY WITHIN the interval. - If
flexibility == 1
: gaps may OVERLAP the edges of the interval. - If
flexibility == 2
: gaps may ABUT the edges of the interval.
Returns
(True, None)
or(False, first_failure_interval)
.- If
- intervals – optional list of
-
cardinal_pythonlib.interval.
convert_duration
(duration: datetime.timedelta, units: str) → Optional[float][source]¶ Convert a
datetime.timedelta
object – a duration – into other units. Possible units:s
,sec
,seconds
m
,min
,minutes
h
,hr
,hours
d
,days
w
,weeks
y
,years
-
cardinal_pythonlib.interval.
formatdt
(date: datetime.date, include_time: bool = True) → str[source]¶ Formats a
datetime.date
to ISO-8601 basic format, to minute accuracy with no timezone (or, ifinclude_time
isFalse
, omit the time).
-
cardinal_pythonlib.interval.
is_normal_uk_working_day
(date: datetime.date) → bool[source]¶ Is the specified date (a
datetime.date
object) a normal working day, i.e. not a weekend or a bank holiday?
-
cardinal_pythonlib.interval.
is_saturday
(date: datetime.date) → bool[source]¶ Is the specified date (a
datetime.date
object) a Saturday?
-
cardinal_pythonlib.interval.
is_sunday
(date: datetime.date) → bool[source]¶ Is the specified date (a
datetime.date
object) a Sunday?