Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pendulum/time.py: 39%
134 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-30 06:11 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-30 06:11 +0000
1from __future__ import annotations
3import datetime
5from datetime import time
6from datetime import timedelta
7from typing import TYPE_CHECKING
8from typing import Optional
9from typing import cast
10from typing import overload
12import pendulum
14from pendulum.constants import SECS_PER_HOUR
15from pendulum.constants import SECS_PER_MIN
16from pendulum.constants import USECS_PER_SEC
17from pendulum.duration import AbsoluteDuration
18from pendulum.duration import Duration
19from pendulum.mixins.default import FormattableMixin
20from pendulum.tz.timezone import UTC
23if TYPE_CHECKING:
24 from typing_extensions import Literal
25 from typing_extensions import Self
26 from typing_extensions import SupportsIndex
28 from pendulum.tz.timezone import FixedTimezone
29 from pendulum.tz.timezone import Timezone
32class Time(FormattableMixin, time):
33 """
34 Represents a time instance as hour, minute, second, microsecond.
35 """
37 @classmethod
38 def instance(
39 cls, t: time, tz: str | Timezone | FixedTimezone | datetime.tzinfo | None = UTC
40 ) -> Self:
41 tz = t.tzinfo or tz
43 if tz is not None:
44 tz = pendulum._safe_timezone(tz)
46 return cls(t.hour, t.minute, t.second, t.microsecond, tzinfo=tz, fold=t.fold)
48 # String formatting
49 def __repr__(self) -> str:
50 us = ""
51 if self.microsecond:
52 us = f", {self.microsecond}"
54 tzinfo = ""
55 if self.tzinfo:
56 tzinfo = f", tzinfo={self.tzinfo!r}"
58 return (
59 f"{self.__class__.__name__}"
60 f"({self.hour}, {self.minute}, {self.second}{us}{tzinfo})"
61 )
63 # Comparisons
65 def closest(self, dt1: Time | time, dt2: Time | time) -> Self:
66 """
67 Get the closest time from the instance.
68 """
69 dt1 = self.__class__(dt1.hour, dt1.minute, dt1.second, dt1.microsecond)
70 dt2 = self.__class__(dt2.hour, dt2.minute, dt2.second, dt2.microsecond)
72 if self.diff(dt1).in_seconds() < self.diff(dt2).in_seconds():
73 return dt1
75 return dt2
77 def farthest(self, dt1: Time | time, dt2: Time | time) -> Self:
78 """
79 Get the farthest time from the instance.
80 """
81 dt1 = self.__class__(dt1.hour, dt1.minute, dt1.second, dt1.microsecond)
82 dt2 = self.__class__(dt2.hour, dt2.minute, dt2.second, dt2.microsecond)
84 if self.diff(dt1).in_seconds() > self.diff(dt2).in_seconds():
85 return dt1
87 return dt2
89 # ADDITIONS AND SUBSTRACTIONS
91 def add(
92 self, hours: int = 0, minutes: int = 0, seconds: int = 0, microseconds: int = 0
93 ) -> Time:
94 """
95 Add duration to the instance.
97 :param hours: The number of hours
98 :param minutes: The number of minutes
99 :param seconds: The number of seconds
100 :param microseconds: The number of microseconds
101 """
102 from pendulum.datetime import DateTime
104 return (
105 DateTime.EPOCH.at(self.hour, self.minute, self.second, self.microsecond)
106 .add(
107 hours=hours, minutes=minutes, seconds=seconds, microseconds=microseconds
108 )
109 .time()
110 )
112 def subtract(
113 self, hours: int = 0, minutes: int = 0, seconds: int = 0, microseconds: int = 0
114 ) -> Time:
115 """
116 Add duration to the instance.
118 :param hours: The number of hours
119 :type hours: int
121 :param minutes: The number of minutes
122 :type minutes: int
124 :param seconds: The number of seconds
125 :type seconds: int
127 :param microseconds: The number of microseconds
128 :type microseconds: int
130 :rtype: Time
131 """
132 from pendulum.datetime import DateTime
134 return (
135 DateTime.EPOCH.at(self.hour, self.minute, self.second, self.microsecond)
136 .subtract(
137 hours=hours, minutes=minutes, seconds=seconds, microseconds=microseconds
138 )
139 .time()
140 )
142 def add_timedelta(self, delta: datetime.timedelta) -> Time:
143 """
144 Add timedelta duration to the instance.
146 :param delta: The timedelta instance
147 """
148 if delta.days:
149 raise TypeError("Cannot add timedelta with days to Time.")
151 return self.add(seconds=delta.seconds, microseconds=delta.microseconds)
153 def subtract_timedelta(self, delta: datetime.timedelta) -> Time:
154 """
155 Remove timedelta duration from the instance.
157 :param delta: The timedelta instance
158 """
159 if delta.days:
160 raise TypeError("Cannot subtract timedelta with days to Time.")
162 return self.subtract(seconds=delta.seconds, microseconds=delta.microseconds)
164 def __add__(self, other: datetime.timedelta) -> Time:
165 if not isinstance(other, timedelta):
166 return NotImplemented
168 return self.add_timedelta(other)
170 @overload
171 def __sub__(self, other: time) -> pendulum.Duration:
172 ...
174 @overload
175 def __sub__(self, other: datetime.timedelta) -> Time:
176 ...
178 def __sub__(self, other: time | datetime.timedelta) -> pendulum.Duration | Time:
179 if not isinstance(other, (Time, time, timedelta)):
180 return NotImplemented
182 if isinstance(other, timedelta):
183 return self.subtract_timedelta(other)
185 if isinstance(other, time):
186 if other.tzinfo is not None:
187 raise TypeError("Cannot subtract aware times to or from Time.")
189 other = self.__class__(
190 other.hour, other.minute, other.second, other.microsecond
191 )
193 return other.diff(self, False)
195 @overload
196 def __rsub__(self, other: time) -> pendulum.Duration:
197 ...
199 @overload
200 def __rsub__(self, other: datetime.timedelta) -> Time:
201 ...
203 def __rsub__(self, other: time | datetime.timedelta) -> pendulum.Duration | Time:
204 if not isinstance(other, (Time, time)):
205 return NotImplemented
207 if isinstance(other, time):
208 if other.tzinfo is not None:
209 raise TypeError("Cannot subtract aware times to or from Time.")
211 other = self.__class__(
212 other.hour, other.minute, other.second, other.microsecond
213 )
215 return other.__sub__(self)
217 # DIFFERENCES
219 def diff(self, dt: time | None = None, abs: bool = True) -> Duration:
220 """
221 Returns the difference between two Time objects as an Duration.
223 :param dt: The time to subtract from
224 :param abs: Whether to return an absolute duration or not
225 """
226 if dt is None:
227 dt = pendulum.now().time()
228 else:
229 dt = self.__class__(dt.hour, dt.minute, dt.second, dt.microsecond)
231 us1 = (
232 self.hour * SECS_PER_HOUR + self.minute * SECS_PER_MIN + self.second
233 ) * USECS_PER_SEC
235 us2 = (
236 dt.hour * SECS_PER_HOUR + dt.minute * SECS_PER_MIN + dt.second
237 ) * USECS_PER_SEC
239 klass = Duration
240 if abs:
241 klass = AbsoluteDuration
243 return klass(microseconds=us2 - us1)
245 def diff_for_humans(
246 self,
247 other: time | None = None,
248 absolute: bool = False,
249 locale: str | None = None,
250 ) -> str:
251 """
252 Get the difference in a human readable format in the current locale.
254 :param dt: The time to subtract from
255 :param absolute: removes time difference modifiers ago, after, etc
256 :param locale: The locale to use for localization
257 """
258 is_now = other is None
260 if is_now:
261 other = pendulum.now().time()
263 diff = self.diff(other)
265 return pendulum.format_diff(diff, is_now, absolute, locale)
267 # Compatibility methods
269 def replace(
270 self,
271 hour: SupportsIndex | None = None,
272 minute: SupportsIndex | None = None,
273 second: SupportsIndex | None = None,
274 microsecond: SupportsIndex | None = None,
275 tzinfo: bool | datetime.tzinfo | Literal[True] | None = True,
276 fold: int = 0,
277 ) -> Self:
278 if tzinfo is True:
279 tzinfo = self.tzinfo
281 hour = hour if hour is not None else self.hour
282 minute = minute if minute is not None else self.minute
283 second = second if second is not None else self.second
284 microsecond = microsecond if microsecond is not None else self.microsecond
286 t = super().replace(
287 hour,
288 minute,
289 second,
290 microsecond,
291 tzinfo=cast(Optional[datetime.tzinfo], tzinfo),
292 fold=fold,
293 )
294 return self.__class__(
295 t.hour, t.minute, t.second, t.microsecond, tzinfo=t.tzinfo
296 )
298 def __getnewargs__(self) -> tuple[Time]:
299 return (self,)
301 def _get_state(
302 self, protocol: SupportsIndex = 3
303 ) -> tuple[int, int, int, int, datetime.tzinfo | None]:
304 tz = self.tzinfo
306 return self.hour, self.minute, self.second, self.microsecond, tz
308 def __reduce__(
309 self,
310 ) -> tuple[type[Time], tuple[int, int, int, int, datetime.tzinfo | None]]:
311 return self.__reduce_ex__(2)
313 def __reduce_ex__(
314 self, protocol: SupportsIndex
315 ) -> tuple[type[Time], tuple[int, int, int, int, datetime.tzinfo | None]]:
316 return self.__class__, self._get_state(protocol)
319Time.min = Time(0, 0, 0)
320Time.max = Time(23, 59, 59, 999999)
321Time.resolution = Duration(microseconds=1)