Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pendulum/time.py: 37%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

130 statements  

1from __future__ import annotations 

2 

3import datetime 

4 

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 

11 

12import pendulum 

13 

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 

21 

22 

23if TYPE_CHECKING: 

24 from typing_extensions import Literal 

25 from typing_extensions import Self 

26 from typing_extensions import SupportsIndex 

27 

28 from pendulum.tz.timezone import FixedTimezone 

29 from pendulum.tz.timezone import Timezone 

30 

31 

32class Time(FormattableMixin, time): 

33 """ 

34 Represents a time instance as hour, minute, second, microsecond. 

35 """ 

36 

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 

42 

43 if tz is not None: 

44 tz = pendulum._safe_timezone(tz) 

45 

46 return cls(t.hour, t.minute, t.second, t.microsecond, tzinfo=tz, fold=t.fold) 

47 

48 # String formatting 

49 def __repr__(self) -> str: 

50 us = "" 

51 if self.microsecond: 

52 us = f", {self.microsecond}" 

53 

54 tzinfo = "" 

55 if self.tzinfo: 

56 tzinfo = f", tzinfo={self.tzinfo!r}" 

57 

58 return ( 

59 f"{self.__class__.__name__}" 

60 f"({self.hour}, {self.minute}, {self.second}{us}{tzinfo})" 

61 ) 

62 

63 # Comparisons 

64 

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) 

71 

72 if self.diff(dt1).in_seconds() < self.diff(dt2).in_seconds(): 

73 return dt1 

74 

75 return dt2 

76 

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) 

83 

84 if self.diff(dt1).in_seconds() > self.diff(dt2).in_seconds(): 

85 return dt1 

86 

87 return dt2 

88 

89 # ADDITIONS AND SUBSTRACTIONS 

90 

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. 

96 

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 

103 

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 ) 

111 

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. 

117 

118 :param hours: The number of hours 

119 :type hours: int 

120 

121 :param minutes: The number of minutes 

122 :type minutes: int 

123 

124 :param seconds: The number of seconds 

125 :type seconds: int 

126 

127 :param microseconds: The number of microseconds 

128 :type microseconds: int 

129 

130 :rtype: Time 

131 """ 

132 from pendulum.datetime import DateTime 

133 

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 ) 

141 

142 def add_timedelta(self, delta: datetime.timedelta) -> Time: 

143 """ 

144 Add timedelta duration to the instance. 

145 

146 :param delta: The timedelta instance 

147 """ 

148 if delta.days: 

149 raise TypeError("Cannot add timedelta with days to Time.") 

150 

151 return self.add(seconds=delta.seconds, microseconds=delta.microseconds) 

152 

153 def subtract_timedelta(self, delta: datetime.timedelta) -> Time: 

154 """ 

155 Remove timedelta duration from the instance. 

156 

157 :param delta: The timedelta instance 

158 """ 

159 if delta.days: 

160 raise TypeError("Cannot subtract timedelta with days to Time.") 

161 

162 return self.subtract(seconds=delta.seconds, microseconds=delta.microseconds) 

163 

164 def __add__(self, other: datetime.timedelta) -> Time: 

165 if not isinstance(other, timedelta): 

166 return NotImplemented 

167 

168 return self.add_timedelta(other) 

169 

170 @overload 

171 def __sub__(self, other: time) -> pendulum.Duration: ... 

172 

173 @overload 

174 def __sub__(self, other: datetime.timedelta) -> Time: ... 

175 

176 def __sub__(self, other: time | datetime.timedelta) -> pendulum.Duration | Time: 

177 if not isinstance(other, (Time, time, timedelta)): 

178 return NotImplemented 

179 

180 if isinstance(other, timedelta): 

181 return self.subtract_timedelta(other) 

182 

183 if isinstance(other, time): 

184 if other.tzinfo is not None: 

185 raise TypeError("Cannot subtract aware times to or from Time.") 

186 

187 other = self.__class__( 

188 other.hour, other.minute, other.second, other.microsecond 

189 ) 

190 

191 return other.diff(self, False) 

192 

193 @overload 

194 def __rsub__(self, other: time) -> pendulum.Duration: ... 

195 

196 @overload 

197 def __rsub__(self, other: datetime.timedelta) -> Time: ... 

198 

199 def __rsub__(self, other: time | datetime.timedelta) -> pendulum.Duration | Time: 

200 if not isinstance(other, (Time, time)): 

201 return NotImplemented 

202 

203 if isinstance(other, time): 

204 if other.tzinfo is not None: 

205 raise TypeError("Cannot subtract aware times to or from Time.") 

206 

207 other = self.__class__( 

208 other.hour, other.minute, other.second, other.microsecond 

209 ) 

210 

211 return other.__sub__(self) 

212 

213 # DIFFERENCES 

214 

215 def diff(self, dt: time | None = None, abs: bool = True) -> Duration: 

216 """ 

217 Returns the difference between two Time objects as an Duration. 

218 

219 :param dt: The time to subtract from 

220 :param abs: Whether to return an absolute duration or not 

221 """ 

222 if dt is None: 

223 dt = pendulum.now().time() 

224 else: 

225 dt = self.__class__(dt.hour, dt.minute, dt.second, dt.microsecond) 

226 

227 us1 = ( 

228 self.hour * SECS_PER_HOUR + self.minute * SECS_PER_MIN + self.second 

229 ) * USECS_PER_SEC 

230 

231 us2 = ( 

232 dt.hour * SECS_PER_HOUR + dt.minute * SECS_PER_MIN + dt.second 

233 ) * USECS_PER_SEC 

234 

235 klass = Duration 

236 if abs: 

237 klass = AbsoluteDuration 

238 

239 return klass(microseconds=us2 - us1) 

240 

241 def diff_for_humans( 

242 self, 

243 other: time | None = None, 

244 absolute: bool = False, 

245 locale: str | None = None, 

246 ) -> str: 

247 """ 

248 Get the difference in a human readable format in the current locale. 

249 

250 :param dt: The time to subtract from 

251 :param absolute: removes time difference modifiers ago, after, etc 

252 :param locale: The locale to use for localization 

253 """ 

254 is_now = other is None 

255 

256 if is_now: 

257 other = pendulum.now().time() 

258 

259 diff = self.diff(other) 

260 

261 return pendulum.format_diff(diff, is_now, absolute, locale) 

262 

263 # Compatibility methods 

264 

265 def replace( 

266 self, 

267 hour: SupportsIndex | None = None, 

268 minute: SupportsIndex | None = None, 

269 second: SupportsIndex | None = None, 

270 microsecond: SupportsIndex | None = None, 

271 tzinfo: bool | datetime.tzinfo | Literal[True] | None = True, 

272 fold: int = 0, 

273 ) -> Self: 

274 if tzinfo is True: 

275 tzinfo = self.tzinfo 

276 

277 hour = hour if hour is not None else self.hour 

278 minute = minute if minute is not None else self.minute 

279 second = second if second is not None else self.second 

280 microsecond = microsecond if microsecond is not None else self.microsecond 

281 

282 t = super().replace( 

283 hour, 

284 minute, 

285 second, 

286 microsecond, 

287 tzinfo=cast("Optional[datetime.tzinfo]", tzinfo), 

288 fold=fold, 

289 ) 

290 return self.__class__( 

291 t.hour, t.minute, t.second, t.microsecond, tzinfo=t.tzinfo 

292 ) 

293 

294 def __getnewargs__(self) -> tuple[Time]: 

295 return (self,) 

296 

297 def _get_state( 

298 self, protocol: SupportsIndex = 3 

299 ) -> tuple[int, int, int, int, datetime.tzinfo | None]: 

300 tz = self.tzinfo 

301 

302 return self.hour, self.minute, self.second, self.microsecond, tz 

303 

304 def __reduce__( 

305 self, 

306 ) -> tuple[type[Time], tuple[int, int, int, int, datetime.tzinfo | None]]: 

307 return self.__reduce_ex__(2) 

308 

309 def __reduce_ex__( 

310 self, protocol: SupportsIndex 

311 ) -> tuple[type[Time], tuple[int, int, int, int, datetime.tzinfo | None]]: 

312 return self.__class__, self._get_state(protocol) 

313 

314 

315Time.min = Time(0, 0, 0) 

316Time.max = Time(23, 59, 59, 999999) 

317Time.resolution = Duration(microseconds=1)