diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-17 14:36:26 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-17 14:36:33 +0000 |
commit | 665666d6f4213da8db57ebb480947b7caf1fe382 (patch) | |
tree | 0cac5d322dfe861a6de62b04fb916cef6dbe4510 /pendulum/interval.py | |
parent | Releasing debian version 3.0.0~a1-2. (diff) | |
download | pendulum-665666d6f4213da8db57ebb480947b7caf1fe382.tar.xz pendulum-665666d6f4213da8db57ebb480947b7caf1fe382.zip |
Merging upstream version 3.0.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'pendulum/interval.py')
-rw-r--r-- | pendulum/interval.py | 448 |
1 files changed, 0 insertions, 448 deletions
diff --git a/pendulum/interval.py b/pendulum/interval.py deleted file mode 100644 index f20042b..0000000 --- a/pendulum/interval.py +++ /dev/null @@ -1,448 +0,0 @@ -from __future__ import annotations - -import operator - -from datetime import date -from datetime import datetime -from datetime import timedelta -from typing import TYPE_CHECKING -from typing import Iterator -from typing import Union -from typing import cast -from typing import overload - -import pendulum - -from pendulum.constants import MONTHS_PER_YEAR -from pendulum.duration import Duration -from pendulum.helpers import precise_diff - -if TYPE_CHECKING: - from typing import SupportsIndex - - from pendulum.helpers import PreciseDiff - from pendulum.locales.locale import Locale # noqa - - -class Interval(Duration): - """ - A period of time between two datetimes. - """ - - @overload - def __new__( - cls, - start: pendulum.DateTime | datetime, - end: pendulum.DateTime | datetime, - absolute: bool = False, - ) -> Interval: - ... - - @overload - def __new__( - cls, - start: pendulum.Date | date, - end: pendulum.Date | date, - absolute: bool = False, - ) -> Interval: - ... - - def __new__( - cls, - start: pendulum.DateTime | pendulum.Date | datetime | date, - end: pendulum.DateTime | pendulum.Date | datetime | date, - absolute: bool = False, - ) -> Interval: - if ( - isinstance(start, datetime) - and not isinstance(end, datetime) - or not isinstance(start, datetime) - and isinstance(end, datetime) - ): - raise ValueError("Both start and end of a Period must have the same type") - - if ( - isinstance(start, datetime) - and isinstance(end, datetime) - and ( - start.tzinfo is None - and end.tzinfo is not None - or start.tzinfo is not None - and end.tzinfo is None - ) - ): - raise TypeError("can't compare offset-naive and offset-aware datetimes") - - if absolute and start > end: - end, start = start, end - - _start = start - _end = end - if isinstance(start, pendulum.DateTime): - _start = datetime( - start.year, - start.month, - start.day, - start.hour, - start.minute, - start.second, - start.microsecond, - tzinfo=start.tzinfo, - fold=start.fold, - ) - elif isinstance(start, pendulum.Date): - _start = date(start.year, start.month, start.day) - - if isinstance(end, pendulum.DateTime): - _end = datetime( - end.year, - end.month, - end.day, - end.hour, - end.minute, - end.second, - end.microsecond, - tzinfo=end.tzinfo, - fold=end.fold, - ) - elif isinstance(end, pendulum.Date): - _end = date(end.year, end.month, end.day) - - # Fixing issues with datetime.__sub__() - # not handling offsets if the tzinfo is the same - if ( - isinstance(_start, datetime) - and isinstance(_end, datetime) - and _start.tzinfo is _end.tzinfo - ): - if _start.tzinfo is not None: - offset = cast(timedelta, cast(datetime, start).utcoffset()) - _start = (_start - offset).replace(tzinfo=None) - - if isinstance(end, datetime) and _end.tzinfo is not None: - offset = cast(timedelta, end.utcoffset()) - _end = (_end - offset).replace(tzinfo=None) - - delta: timedelta = _end - _start # type: ignore[operator] - - return cast(Interval, super().__new__(cls, seconds=delta.total_seconds())) - - def __init__( - self, - start: pendulum.DateTime | pendulum.Date | datetime | date, - end: pendulum.DateTime | pendulum.Date | datetime | date, - absolute: bool = False, - ) -> None: - super().__init__() - - _start: pendulum.DateTime | pendulum.Date | datetime | date - if not isinstance(start, pendulum.Date): - if isinstance(start, datetime): - start = pendulum.instance(start) - else: - start = pendulum.date(start.year, start.month, start.day) - - _start = start - else: - if isinstance(start, pendulum.DateTime): - _start = datetime( - start.year, - start.month, - start.day, - start.hour, - start.minute, - start.second, - start.microsecond, - tzinfo=start.tzinfo, - ) - else: - _start = date(start.year, start.month, start.day) - - _end: pendulum.DateTime | pendulum.Date | datetime | date - if not isinstance(end, pendulum.Date): - if isinstance(end, datetime): - end = pendulum.instance(end) - else: - end = pendulum.date(end.year, end.month, end.day) - - _end = end - else: - if isinstance(end, pendulum.DateTime): - _end = datetime( - end.year, - end.month, - end.day, - end.hour, - end.minute, - end.second, - end.microsecond, - tzinfo=end.tzinfo, - ) - else: - _end = date(end.year, end.month, end.day) - - self._invert = False - if start > end: - self._invert = True - - if absolute: - end, start = start, end - _end, _start = _start, _end - - self._absolute = absolute - self._start: pendulum.DateTime | pendulum.Date = start - self._end: pendulum.DateTime | pendulum.Date = end - self._delta: PreciseDiff = precise_diff(_start, _end) - - @property - def years(self) -> int: - return self._delta.years - - @property - def months(self) -> int: - return self._delta.months - - @property - def weeks(self) -> int: - return abs(self._delta.days) // 7 * self._sign(self._delta.days) - - @property - def days(self) -> int: - return self._days - - @property - def remaining_days(self) -> int: - return abs(self._delta.days) % 7 * self._sign(self._days) - - @property - def hours(self) -> int: - return self._delta.hours - - @property - def minutes(self) -> int: - return self._delta.minutes - - @property - def start(self) -> pendulum.DateTime | pendulum.Date | datetime | date: - return self._start - - @property - def end(self) -> pendulum.DateTime | pendulum.Date | datetime | date: - return self._end - - def in_years(self) -> int: - """ - Gives the duration of the Period in full years. - """ - return self.years - - def in_months(self) -> int: - """ - Gives the duration of the Period in full months. - """ - return self.years * MONTHS_PER_YEAR + self.months - - def in_weeks(self) -> int: - days = self.in_days() - sign = 1 - - if days < 0: - sign = -1 - - return sign * (abs(days) // 7) - - def in_days(self) -> int: - return self._delta.total_days - - def in_words(self, locale: str | None = None, separator: str = " ") -> str: - """ - Get the current interval in words in the current locale. - - Ex: 6 jours 23 heures 58 minutes - - :param locale: The locale to use. Defaults to current locale. - :param separator: The separator to use between each unit - """ - from pendulum.locales.locale import Locale # noqa - - periods = [ - ("year", self.years), - ("month", self.months), - ("week", self.weeks), - ("day", self.remaining_days), - ("hour", self.hours), - ("minute", self.minutes), - ("second", self.remaining_seconds), - ] - loaded_locale: Locale = Locale.load(locale or pendulum.get_locale()) - parts = [] - for period in periods: - unit, period_count = period - if abs(period_count) > 0: - translation = loaded_locale.translation( - f"units.{unit}.{loaded_locale.plural(abs(period_count))}" - ) - parts.append(translation.format(period_count)) - - if not parts: - count: str | int = 0 - if abs(self.microseconds) > 0: - unit = f"units.second.{loaded_locale.plural(1)}" - count = f"{abs(self.microseconds) / 1e6:.2f}" - else: - unit = f"units.microsecond.{loaded_locale.plural(0)}" - - translation = loaded_locale.translation(unit) - parts.append(translation.format(count)) - - return separator.join(parts) - - def range( - self, unit: str, amount: int = 1 - ) -> Iterator[pendulum.DateTime | pendulum.Date]: - method = "add" - op = operator.le - if not self._absolute and self.invert: - method = "subtract" - op = operator.ge - - start, end = self.start, self.end - - i = amount - while op(start, end): - yield cast(Union[pendulum.DateTime, pendulum.Date], start) - - start = getattr(self.start, method)(**{unit: i}) - - i += amount - - def as_interval(self) -> Duration: - """ - Return the Period as a Duration. - """ - return Duration(seconds=self.total_seconds()) - - def __iter__(self) -> Iterator[pendulum.DateTime | pendulum.Date]: - return self.range("days") - - def __contains__( - self, item: datetime | date | pendulum.DateTime | pendulum.Date - ) -> bool: - return self.start <= item <= self.end - - def __add__(self, other: timedelta) -> Duration: - return self.as_interval().__add__(other) - - __radd__ = __add__ - - def __sub__(self, other: timedelta) -> Duration: - return self.as_interval().__sub__(other) - - def __neg__(self) -> Interval: - return self.__class__(self.end, self.start, self._absolute) - - def __mul__(self, other: int | float) -> Duration: - return self.as_interval().__mul__(other) - - __rmul__ = __mul__ - - @overload - def __floordiv__(self, other: timedelta) -> int: - ... - - @overload - def __floordiv__(self, other: int) -> Duration: - ... - - def __floordiv__(self, other: int | timedelta) -> int | Duration: - return self.as_interval().__floordiv__(other) - - __div__ = __floordiv__ # type: ignore[assignment] - - @overload - def __truediv__(self, other: timedelta) -> float: - ... - - @overload - def __truediv__(self, other: float) -> Duration: - ... - - def __truediv__(self, other: float | timedelta) -> Duration | float: - return self.as_interval().__truediv__(other) - - def __mod__(self, other: timedelta) -> Duration: - return self.as_interval().__mod__(other) - - def __divmod__(self, other: timedelta) -> tuple[int, Duration]: - return self.as_interval().__divmod__(other) - - def __abs__(self) -> Interval: - return self.__class__(self.start, self.end, absolute=True) - - def __repr__(self) -> str: - return f"<Period [{self._start} -> {self._end}]>" - - def __str__(self) -> str: - return self.__repr__() - - def _cmp(self, other: timedelta) -> int: - # Only needed for PyPy - assert isinstance(other, timedelta) - - if isinstance(other, Interval): - other = other.as_timedelta() - - td = self.as_timedelta() - - return 0 if td == other else 1 if td > other else -1 - - def _getstate( - self, protocol: SupportsIndex = 3 - ) -> tuple[ - pendulum.DateTime | pendulum.Date | datetime | date, - pendulum.DateTime | pendulum.Date | datetime | date, - bool, - ]: - start, end = self.start, self.end - - if self._invert and self._absolute: - end, start = start, end - - return start, end, self._absolute - - def __reduce__( - self, - ) -> tuple[ - type[Interval], - tuple[ - pendulum.DateTime | pendulum.Date | datetime | date, - pendulum.DateTime | pendulum.Date | datetime | date, - bool, - ], - ]: - return self.__reduce_ex__(2) - - def __reduce_ex__( - self, protocol: SupportsIndex - ) -> tuple[ - type[Interval], - tuple[ - pendulum.DateTime | pendulum.Date | datetime | date, - pendulum.DateTime | pendulum.Date | datetime | date, - bool, - ], - ]: - return self.__class__, self._getstate(protocol) - - def __hash__(self) -> int: - return hash((self.start, self.end, self._absolute)) - - def __eq__(self, other: object) -> bool: - if isinstance(other, Interval): - return (self.start, self.end, self._absolute) == ( - other.start, - other.end, - other._absolute, - ) - else: - return self.as_interval() == other |