impuls.tools.temporal

final class impuls.tools.temporal.BoundedDateRange(start: Date, end: Date)

Bases: _DateRangeABC

RightUnboundedDateRange is a range of all dates between start and end, inclusive.

__contains__(x: Date) bool

Checks if Date is contained within a DateRange.

__iter__() Iterator[Date]

Iterates over all dates covered by a DateRange.

For LeftUnbounded and RightUnbounded ranges the iterator will be infinite. Trying to iterate over InfiniteDateRange throws RuntimeError.

difference(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are in self, but not in o. Raises ArithmeticError if difference of ranges would not be contiguous.

intersection(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates from self that are also covered in o.

isdisjoint(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if self and o have no dates in common.

issubset(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if all dates covered by self are also covered by o.

len() float

Returns the number of days covered by the DateRange. Always a non-negative integer, or inf (for unbounded ranges).

union(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are either in self or o. Raises ArithmeticError if union of ranges would not be contiguous.

property compressed_weekdays: int

Bitset of weekdays covered by the DateRange. 1 << 0 is Monday, 1 << 1 is Tuesday and so on, up to Sunday, 1 << 6.

Always 0b111_1111 (all weekdays) for unbounded DateRanges.

final class impuls.tools.temporal.EmptyDateRange

Bases: _DateRangeABC

EmptyDateRange is a range of dates without any dates.

__contains__(x: Date) bool

Checks if Date is contained within a DateRange.

__iter__() Iterator[Date]

Iterates over all dates covered by a DateRange.

For LeftUnbounded and RightUnbounded ranges the iterator will be infinite. Trying to iterate over InfiniteDateRange throws RuntimeError.

difference(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are in self, but not in o. Raises ArithmeticError if difference of ranges would not be contiguous.

intersection(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates from self that are also covered in o.

isdisjoint(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if self and o have no dates in common.

issubset(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if all dates covered by self are also covered by o.

len() float

Returns the number of days covered by the DateRange. Always a non-negative integer, or inf (for unbounded ranges).

union(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are either in self or o. Raises ArithmeticError if union of ranges would not be contiguous.

property compressed_weekdays: int

Bitset of weekdays covered by the DateRange. 1 << 0 is Monday, 1 << 1 is Tuesday and so on, up to Sunday, 1 << 6.

Always 0b111_1111 (all weekdays) for unbounded DateRanges.

final class impuls.tools.temporal.InfiniteDateRange

Bases: _DateRangeABC

InfiniteDateRange is a range of dates covering every date.

__contains__(x: Date) bool

Checks if Date is contained within a DateRange.

__iter__() Iterator[Date]

Iterates over all dates covered by a DateRange.

For LeftUnbounded and RightUnbounded ranges the iterator will be infinite. Trying to iterate over InfiniteDateRange throws RuntimeError.

difference(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are in self, but not in o. Raises ArithmeticError if difference of ranges would not be contiguous.

intersection(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates from self that are also covered in o.

isdisjoint(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if self and o have no dates in common.

issubset(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if all dates covered by self are also covered by o.

len() float

Returns the number of days covered by the DateRange. Always a non-negative integer, or inf (for unbounded ranges).

union(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are either in self or o. Raises ArithmeticError if union of ranges would not be contiguous.

property compressed_weekdays: int

Bitset of weekdays covered by the DateRange. 1 << 0 is Monday, 1 << 1 is Tuesday and so on, up to Sunday, 1 << 6.

Always 0b111_1111 (all weekdays) for unbounded DateRanges.

final class impuls.tools.temporal.LeftUnboundedDateRange(end: Date)

Bases: _DateRangeABC

LeftUnboundedDateRange is a range of all dates up to (and including) the end date.

__contains__(x: Date) bool

Checks if Date is contained within a DateRange.

__iter__() Iterator[Date]

Iterates over all dates covered by a DateRange.

For LeftUnbounded and RightUnbounded ranges the iterator will be infinite. Trying to iterate over InfiniteDateRange throws RuntimeError.

difference(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are in self, but not in o. Raises ArithmeticError if difference of ranges would not be contiguous.

intersection(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates from self that are also covered in o.

isdisjoint(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if self and o have no dates in common.

issubset(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if all dates covered by self are also covered by o.

len() float

Returns the number of days covered by the DateRange. Always a non-negative integer, or inf (for unbounded ranges).

union(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are either in self or o. Raises ArithmeticError if union of ranges would not be contiguous.

property compressed_weekdays: int

Bitset of weekdays covered by the DateRange. 1 << 0 is Monday, 1 << 1 is Tuesday and so on, up to Sunday, 1 << 6.

Always 0b111_1111 (all weekdays) for unbounded DateRanges.

final class impuls.tools.temporal.RightUnboundedDateRange(start: Date)

Bases: _DateRangeABC

RightUnboundedDateRange is a range of all dates starting from the start date.

__contains__(x: Date) bool

Checks if Date is contained within a DateRange.

__iter__() Iterator[Date]

Iterates over all dates covered by a DateRange.

For LeftUnbounded and RightUnbounded ranges the iterator will be infinite. Trying to iterate over InfiniteDateRange throws RuntimeError.

difference(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are in self, but not in o. Raises ArithmeticError if difference of ranges would not be contiguous.

intersection(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates from self that are also covered in o.

isdisjoint(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if self and o have no dates in common.

issubset(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) bool

Returns True if all dates covered by self are also covered by o.

len() float

Returns the number of days covered by the DateRange. Always a non-negative integer, or inf (for unbounded ranges).

union(o: EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange) EmptyDateRange | InfiniteDateRange | LeftUnboundedDateRange | RightUnboundedDateRange | BoundedDateRange

Returns a DateRange which covers dates that are either in self or o. Raises ArithmeticError if union of ranges would not be contiguous.

property compressed_weekdays: int

Bitset of weekdays covered by the DateRange. 1 << 0 is Monday, 1 << 1 is Tuesday and so on, up to Sunday, 1 << 6.

Always 0b111_1111 (all weekdays) for unbounded DateRanges.

impuls.tools.temporal.date_range(start: Date, end: Date) BoundedDateRange
impuls.tools.temporal.date_range(start: Date, end: None = None) RightUnboundedDateRange
impuls.tools.temporal.date_range(start: None, end: Date) LeftUnboundedDateRange

date_range returns a DateRange object for all dates from start to end, inclusive.

Those objects can be iterated over, but also combined using set-like operations with the following methods:

  • isdisjoint

  • issubset (operator <)

  • union (operator |)

  • intersection (operator &)

  • difference (operator -)

  • (operator ==)

DateRange instances are hashable, and can be used as dictionary keys. DateRange objects are also iterable (with the exception of InfiniteDateRange), but iterators with start=None or end=None are infinite.

If start is None, returns LeftUnboundedDateRange - a DateRange without a start bound.

If end is None, returns RightUnboundedDateRange - a DateRange without an end bound.

However, if both start and end are None - an exception is raised, please explicitly construct EmptyDateRange or InfiniteDateRange.

impuls.tools.temporal.get_european_railway_schedule_revision(for_day: date | None = None) str

Gets the name of the yearly European railway schedule revision active on the provided day, or today if that is missing.

The yearly schedule revision changes on midnight after (think 24:00) the 2nd Saturday of december. This means that for the 2nd Saturday of December we actually return the old revision, as the new schedules only start applying from the following Sunday.

The returned string is the year the revision went live, dash, then the following year.

>>> get_european_railway_schedule_revision(date(2025, 12, 1))
'2024-2025'
>>> get_european_railway_schedule_revision(date(2025, 12, 13))
'2024-2025'
>>> get_european_railway_schedule_revision(date(2025, 12, 14))
'2025-2026'
>>> get_european_railway_schedule_revision(date(2025, 12, 31))
'2025-2026'
>>> get_european_railway_schedule_revision(date(2025, 12, 31))
'2025-2026'
>>> get_european_railway_schedule_revision(date(2024, 12, 14))
'2023-2024'
>>> get_european_railway_schedule_revision(date(2024, 12, 15))
'2024-2025'
impuls.tools.temporal.DateRange = ForwardRef('EmptyDateRange') | ForwardRef('InfiniteDateRange') | ForwardRef('LeftUnboundedDateRange') | ForwardRef('RightUnboundedDateRange') | ForwardRef('BoundedDateRange')

DateRange is any type representing a contiguous range of dates.

Infinite, LeftUnbounded and RightUnbounded ranges cover infinitely many days.