From 1199780155f666b6806d563a29d093a251664009 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 30 Jan 2021 09:13:47 +0100 Subject: Adding upstream version 2.1.2. Signed-off-by: Daniel Baumann --- pendulum/time.py | 284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 pendulum/time.py (limited to 'pendulum/time.py') diff --git a/pendulum/time.py b/pendulum/time.py new file mode 100644 index 0000000..e72972d --- /dev/null +++ b/pendulum/time.py @@ -0,0 +1,284 @@ +from __future__ import absolute_import + +from datetime import time +from datetime import timedelta + +import pendulum + +from .constants import SECS_PER_HOUR +from .constants import SECS_PER_MIN +from .constants import USECS_PER_SEC +from .duration import AbsoluteDuration +from .duration import Duration +from .mixins.default import FormattableMixin + + +class Time(FormattableMixin, time): + """ + Represents a time instance as hour, minute, second, microsecond. + """ + + # String formatting + def __repr__(self): + us = "" + if self.microsecond: + us = ", {}".format(self.microsecond) + + tzinfo = "" + if self.tzinfo: + tzinfo = ", tzinfo={}".format(repr(self.tzinfo)) + + return "{}({}, {}, {}{}{})".format( + self.__class__.__name__, self.hour, self.minute, self.second, us, tzinfo + ) + + # Comparisons + + def closest(self, dt1, dt2): + """ + Get the closest time from the instance. + + :type dt1: Time or time + :type dt2: Time or time + + :rtype: Time + """ + dt1 = self.__class__(dt1.hour, dt1.minute, dt1.second, dt1.microsecond) + dt2 = self.__class__(dt2.hour, dt2.minute, dt2.second, dt2.microsecond) + + if self.diff(dt1).in_seconds() < self.diff(dt2).in_seconds(): + return dt1 + + return dt2 + + def farthest(self, dt1, dt2): + """ + Get the farthest time from the instance. + + :type dt1: Time or time + :type dt2: Time or time + + :rtype: Time + """ + dt1 = self.__class__(dt1.hour, dt1.minute, dt1.second, dt1.microsecond) + dt2 = self.__class__(dt2.hour, dt2.minute, dt2.second, dt2.microsecond) + + if self.diff(dt1).in_seconds() > self.diff(dt2).in_seconds(): + return dt1 + + return dt2 + + # ADDITIONS AND SUBSTRACTIONS + + def add(self, hours=0, minutes=0, seconds=0, microseconds=0): + """ + Add duration to the instance. + + :param hours: The number of hours + :type hours: int + + :param minutes: The number of minutes + :type minutes: int + + :param seconds: The number of seconds + :type seconds: int + + :param microseconds: The number of microseconds + :type microseconds: int + + :rtype: Time + """ + from .datetime import DateTime + + return ( + DateTime.EPOCH.at(self.hour, self.minute, self.second, self.microsecond) + .add( + hours=hours, minutes=minutes, seconds=seconds, microseconds=microseconds + ) + .time() + ) + + def subtract(self, hours=0, minutes=0, seconds=0, microseconds=0): + """ + Add duration to the instance. + + :param hours: The number of hours + :type hours: int + + :param minutes: The number of minutes + :type minutes: int + + :param seconds: The number of seconds + :type seconds: int + + :param microseconds: The number of microseconds + :type microseconds: int + + :rtype: Time + """ + from .datetime import DateTime + + return ( + DateTime.EPOCH.at(self.hour, self.minute, self.second, self.microsecond) + .subtract( + hours=hours, minutes=minutes, seconds=seconds, microseconds=microseconds + ) + .time() + ) + + def add_timedelta(self, delta): + """ + Add timedelta duration to the instance. + + :param delta: The timedelta instance + :type delta: datetime.timedelta + + :rtype: Time + """ + if delta.days: + raise TypeError("Cannot add timedelta with days to Time.") + + return self.add(seconds=delta.seconds, microseconds=delta.microseconds) + + def subtract_timedelta(self, delta): + """ + Remove timedelta duration from the instance. + + :param delta: The timedelta instance + :type delta: datetime.timedelta + + :rtype: Time + """ + if delta.days: + raise TypeError("Cannot subtract timedelta with days to Time.") + + return self.subtract(seconds=delta.seconds, microseconds=delta.microseconds) + + def __add__(self, other): + if not isinstance(other, timedelta): + return NotImplemented + + return self.add_timedelta(other) + + def __sub__(self, other): + if not isinstance(other, (Time, time, timedelta)): + return NotImplemented + + if isinstance(other, timedelta): + return self.subtract_timedelta(other) + + if isinstance(other, time): + if other.tzinfo is not None: + raise TypeError("Cannot subtract aware times to or from Time.") + + other = self.__class__( + other.hour, other.minute, other.second, other.microsecond + ) + + return other.diff(self, False) + + def __rsub__(self, other): + if not isinstance(other, (Time, time)): + return NotImplemented + + if isinstance(other, time): + if other.tzinfo is not None: + raise TypeError("Cannot subtract aware times to or from Time.") + + other = self.__class__( + other.hour, other.minute, other.second, other.microsecond + ) + + return other.__sub__(self) + + # DIFFERENCES + + def diff(self, dt=None, abs=True): + """ + Returns the difference between two Time objects as an Duration. + + :type dt: Time or None + + :param abs: Whether to return an absolute interval or not + :type abs: bool + + :rtype: Duration + """ + if dt is None: + dt = pendulum.now().time() + else: + dt = self.__class__(dt.hour, dt.minute, dt.second, dt.microsecond) + + us1 = ( + self.hour * SECS_PER_HOUR + self.minute * SECS_PER_MIN + self.second + ) * USECS_PER_SEC + + us2 = ( + dt.hour * SECS_PER_HOUR + dt.minute * SECS_PER_MIN + dt.second + ) * USECS_PER_SEC + + klass = Duration + if abs: + klass = AbsoluteDuration + + return klass(microseconds=us2 - us1) + + def diff_for_humans(self, other=None, absolute=False, locale=None): + """ + Get the difference in a human readable format in the current locale. + + :type other: Time or time + + :param absolute: removes time difference modifiers ago, after, etc + :type absolute: bool + + :param locale: The locale to use for localization + :type locale: str + + :rtype: str + """ + is_now = other is None + + if is_now: + other = pendulum.now().time() + + diff = self.diff(other) + + return pendulum.format_diff(diff, is_now, absolute, locale) + + # Compatibility methods + + def replace( + self, hour=None, minute=None, second=None, microsecond=None, tzinfo=True + ): + if tzinfo is True: + tzinfo = self.tzinfo + + hour = hour if hour is not None else self.hour + minute = minute if minute is not None else self.minute + second = second if second is not None else self.second + microsecond = microsecond if microsecond is not None else self.microsecond + + t = super(Time, self).replace(hour, minute, second, microsecond, tzinfo=tzinfo) + return self.__class__( + t.hour, t.minute, t.second, t.microsecond, tzinfo=t.tzinfo + ) + + def __getnewargs__(self): + return (self,) + + def _get_state(self, protocol=3): + tz = self.tzinfo + + return (self.hour, self.minute, self.second, self.microsecond, tz) + + def __reduce__(self): + return self.__reduce_ex__(2) + + def __reduce_ex__(self, protocol): + return self.__class__, self._get_state(protocol) + + +Time.min = Time(0, 0, 0) +Time.max = Time(23, 59, 59, 999999) +Time.resolution = Duration(microseconds=1) -- cgit v1.2.3