/rust/registry/src/index.crates.io-1949cf8c6b5b557f/time-0.3.44/src/time.rs
Line | Count | Source |
1 | | //! The [`Time`] struct and its associated `impl`s. |
2 | | |
3 | | #[cfg(feature = "formatting")] |
4 | | use alloc::string::String; |
5 | | use core::cmp::Ordering; |
6 | | use core::hash::{Hash, Hasher}; |
7 | | use core::ops::{Add, Sub}; |
8 | | use core::time::Duration as StdDuration; |
9 | | use core::{fmt, hint}; |
10 | | #[cfg(feature = "formatting")] |
11 | | use std::io; |
12 | | |
13 | | use deranged::{RangedU32, RangedU8}; |
14 | | use num_conv::prelude::*; |
15 | | use powerfmt::ext::FormatterExt; |
16 | | use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay}; |
17 | | |
18 | | use crate::convert::*; |
19 | | #[cfg(feature = "formatting")] |
20 | | use crate::formatting::Formattable; |
21 | | use crate::internal_macros::{cascade, ensure_ranged, impl_add_assign, impl_sub_assign}; |
22 | | #[cfg(feature = "parsing")] |
23 | | use crate::parsing::Parsable; |
24 | | use crate::util::DateAdjustment; |
25 | | use crate::{error, Duration}; |
26 | | |
27 | | /// By explicitly inserting this enum where padding is expected, the compiler is able to better |
28 | | /// perform niche value optimization. |
29 | | #[repr(u8)] |
30 | | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
31 | | pub(crate) enum Padding { |
32 | | #[allow(clippy::missing_docs_in_private_items)] |
33 | | Optimize, |
34 | | } |
35 | | |
36 | | /// The type of the `hour` field of `Time`. |
37 | | type Hours = RangedU8<0, { Hour::per_t::<u8>(Day) - 1 }>; |
38 | | /// The type of the `minute` field of `Time`. |
39 | | type Minutes = RangedU8<0, { Minute::per_t::<u8>(Hour) - 1 }>; |
40 | | /// The type of the `second` field of `Time`. |
41 | | type Seconds = RangedU8<0, { Second::per_t::<u8>(Minute) - 1 }>; |
42 | | /// The type of the `nanosecond` field of `Time`. |
43 | | type Nanoseconds = RangedU32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>; |
44 | | |
45 | | /// The clock time within a given date. Nanosecond precision. |
46 | | /// |
47 | | /// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds |
48 | | /// (either positive or negative). |
49 | | /// |
50 | | /// When comparing two `Time`s, they are assumed to be in the same calendar date. |
51 | | #[derive(Clone, Copy, Eq)] |
52 | | #[cfg_attr(not(docsrs), repr(C))] |
53 | | pub struct Time { |
54 | | // The order of this struct's fields matter! Do not reorder them. |
55 | | |
56 | | // Little endian version |
57 | | #[cfg(target_endian = "little")] |
58 | | nanosecond: Nanoseconds, |
59 | | #[cfg(target_endian = "little")] |
60 | | second: Seconds, |
61 | | #[cfg(target_endian = "little")] |
62 | | minute: Minutes, |
63 | | #[cfg(target_endian = "little")] |
64 | | hour: Hours, |
65 | | #[cfg(target_endian = "little")] |
66 | | padding: Padding, |
67 | | |
68 | | // Big endian version |
69 | | #[cfg(target_endian = "big")] |
70 | | padding: Padding, |
71 | | #[cfg(target_endian = "big")] |
72 | | hour: Hours, |
73 | | #[cfg(target_endian = "big")] |
74 | | minute: Minutes, |
75 | | #[cfg(target_endian = "big")] |
76 | | second: Seconds, |
77 | | #[cfg(target_endian = "big")] |
78 | | nanosecond: Nanoseconds, |
79 | | } |
80 | | |
81 | | impl Hash for Time { |
82 | | #[inline] |
83 | 0 | fn hash<H: Hasher>(&self, state: &mut H) { |
84 | 0 | self.as_u64().hash(state) |
85 | 0 | } |
86 | | } |
87 | | |
88 | | impl PartialEq for Time { |
89 | | #[inline] |
90 | 0 | fn eq(&self, other: &Self) -> bool { |
91 | 0 | self.as_u64().eq(&other.as_u64()) |
92 | 0 | } |
93 | | } |
94 | | |
95 | | impl PartialOrd for Time { |
96 | | #[inline] |
97 | 0 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
98 | 0 | Some(self.cmp(other)) |
99 | 0 | } |
100 | | } |
101 | | |
102 | | impl Ord for Time { |
103 | | #[inline] |
104 | 0 | fn cmp(&self, other: &Self) -> Ordering { |
105 | 0 | self.as_u64().cmp(&other.as_u64()) |
106 | 0 | } |
107 | | } |
108 | | |
109 | | impl Time { |
110 | | /// Provide a representation of `Time` as a `u64`. This value can be used for equality, hashing, |
111 | | /// and ordering. |
112 | | #[inline] |
113 | 0 | pub(crate) const fn as_u64(self) -> u64 { |
114 | | // Safety: `self` is presumed valid because it exists, and any value of `u64` is valid. Size |
115 | | // and alignment are enforced by the compiler. There is no implicit padding in either `Time` |
116 | | // or `u64`. |
117 | 0 | unsafe { core::mem::transmute(self) } |
118 | 0 | } |
119 | | |
120 | | /// A `Time` that is exactly midnight. This is the smallest possible value for a `Time`. |
121 | | /// |
122 | | /// ```rust |
123 | | /// # use time::Time; |
124 | | /// # use time_macros::time; |
125 | | /// assert_eq!(Time::MIDNIGHT, time!(0:00)); |
126 | | /// ``` |
127 | | #[doc(alias = "MIN")] |
128 | | pub const MIDNIGHT: Self = |
129 | | Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN); |
130 | | |
131 | | /// A `Time` that is one nanosecond before midnight. This is the largest possible value for a |
132 | | /// `Time`. |
133 | | /// |
134 | | /// ```rust |
135 | | /// # use time::Time; |
136 | | /// # use time_macros::time; |
137 | | /// assert_eq!(Time::MAX, time!(23:59:59.999_999_999)); |
138 | | /// ``` |
139 | | pub const MAX: Self = |
140 | | Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX); |
141 | | |
142 | | /// Create a `Time` from its components. |
143 | | /// |
144 | | /// # Safety |
145 | | /// |
146 | | /// - `hours` must be in the range `0..=23`. |
147 | | /// - `minutes` must be in the range `0..=59`. |
148 | | /// - `seconds` must be in the range `0..=59`. |
149 | | /// - `nanoseconds` must be in the range `0..=999_999_999`. |
150 | | #[doc(hidden)] |
151 | | #[inline] |
152 | | #[track_caller] |
153 | 0 | pub const unsafe fn __from_hms_nanos_unchecked( |
154 | 0 | hour: u8, |
155 | 0 | minute: u8, |
156 | 0 | second: u8, |
157 | 0 | nanosecond: u32, |
158 | 0 | ) -> Self { |
159 | | // Safety: The caller must uphold the safety invariants. |
160 | | unsafe { |
161 | 0 | Self::from_hms_nanos_ranged( |
162 | 0 | Hours::new_unchecked(hour), |
163 | 0 | Minutes::new_unchecked(minute), |
164 | 0 | Seconds::new_unchecked(second), |
165 | 0 | Nanoseconds::new_unchecked(nanosecond), |
166 | | ) |
167 | | } |
168 | 0 | } Unexecuted instantiation: <time::time::Time>::__from_hms_nanos_unchecked Unexecuted instantiation: <time::time::Time>::__from_hms_nanos_unchecked |
169 | | |
170 | | /// Attempt to create a `Time` from the hour, minute, and second. |
171 | | /// |
172 | | /// ```rust |
173 | | /// # use time::Time; |
174 | | /// assert!(Time::from_hms(1, 2, 3).is_ok()); |
175 | | /// ``` |
176 | | /// |
177 | | /// ```rust |
178 | | /// # use time::Time; |
179 | | /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour. |
180 | | /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute. |
181 | | /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second. |
182 | | /// ``` |
183 | | #[inline] |
184 | 0 | pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> { |
185 | 0 | Ok(Self::from_hms_nanos_ranged( |
186 | 0 | ensure_ranged!(Hours: hour), |
187 | 0 | ensure_ranged!(Minutes: minute), |
188 | 0 | ensure_ranged!(Seconds: second), |
189 | | Nanoseconds::MIN, |
190 | | )) |
191 | 0 | } |
192 | | |
193 | | /// Create a `Time` from the hour, minute, second, and nanosecond. |
194 | | #[inline] |
195 | 0 | pub(crate) const fn from_hms_nanos_ranged( |
196 | 0 | hour: Hours, |
197 | 0 | minute: Minutes, |
198 | 0 | second: Seconds, |
199 | 0 | nanosecond: Nanoseconds, |
200 | 0 | ) -> Self { |
201 | 0 | Self { |
202 | 0 | hour, |
203 | 0 | minute, |
204 | 0 | second, |
205 | 0 | nanosecond, |
206 | 0 | padding: Padding::Optimize, |
207 | 0 | } |
208 | 0 | } Unexecuted instantiation: <time::time::Time>::from_hms_nanos_ranged Unexecuted instantiation: <time::time::Time>::from_hms_nanos_ranged |
209 | | |
210 | | /// Attempt to create a `Time` from the hour, minute, second, and millisecond. |
211 | | /// |
212 | | /// ```rust |
213 | | /// # use time::Time; |
214 | | /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok()); |
215 | | /// ``` |
216 | | /// |
217 | | /// ```rust |
218 | | /// # use time::Time; |
219 | | /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour. |
220 | | /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute. |
221 | | /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second. |
222 | | /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond. |
223 | | /// ``` |
224 | | #[inline] |
225 | 0 | pub const fn from_hms_milli( |
226 | 0 | hour: u8, |
227 | 0 | minute: u8, |
228 | 0 | second: u8, |
229 | 0 | millisecond: u16, |
230 | 0 | ) -> Result<Self, error::ComponentRange> { |
231 | 0 | Ok(Self::from_hms_nanos_ranged( |
232 | 0 | ensure_ranged!(Hours: hour), |
233 | 0 | ensure_ranged!(Minutes: minute), |
234 | 0 | ensure_ranged!(Seconds: second), |
235 | 0 | ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)), |
236 | | )) |
237 | 0 | } |
238 | | |
239 | | /// Attempt to create a `Time` from the hour, minute, second, and microsecond. |
240 | | /// |
241 | | /// ```rust |
242 | | /// # use time::Time; |
243 | | /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok()); |
244 | | /// ``` |
245 | | /// |
246 | | /// ```rust |
247 | | /// # use time::Time; |
248 | | /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour. |
249 | | /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute. |
250 | | /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second. |
251 | | /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond. |
252 | | /// ``` |
253 | | #[inline] |
254 | 0 | pub const fn from_hms_micro( |
255 | 0 | hour: u8, |
256 | 0 | minute: u8, |
257 | 0 | second: u8, |
258 | 0 | microsecond: u32, |
259 | 0 | ) -> Result<Self, error::ComponentRange> { |
260 | 0 | Ok(Self::from_hms_nanos_ranged( |
261 | 0 | ensure_ranged!(Hours: hour), |
262 | 0 | ensure_ranged!(Minutes: minute), |
263 | 0 | ensure_ranged!(Seconds: second), |
264 | 0 | ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)), |
265 | | )) |
266 | 0 | } |
267 | | |
268 | | /// Attempt to create a `Time` from the hour, minute, second, and nanosecond. |
269 | | /// |
270 | | /// ```rust |
271 | | /// # use time::Time; |
272 | | /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok()); |
273 | | /// ``` |
274 | | /// |
275 | | /// ```rust |
276 | | /// # use time::Time; |
277 | | /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour. |
278 | | /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute. |
279 | | /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second. |
280 | | /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond. |
281 | | /// ``` |
282 | | #[inline] |
283 | 0 | pub const fn from_hms_nano( |
284 | 0 | hour: u8, |
285 | 0 | minute: u8, |
286 | 0 | second: u8, |
287 | 0 | nanosecond: u32, |
288 | 0 | ) -> Result<Self, error::ComponentRange> { |
289 | 0 | Ok(Self::from_hms_nanos_ranged( |
290 | 0 | ensure_ranged!(Hours: hour), |
291 | 0 | ensure_ranged!(Minutes: minute), |
292 | 0 | ensure_ranged!(Seconds: second), |
293 | 0 | ensure_ranged!(Nanoseconds: nanosecond), |
294 | | )) |
295 | 0 | } |
296 | | |
297 | | /// Get the clock hour, minute, and second. |
298 | | /// |
299 | | /// ```rust |
300 | | /// # use time_macros::time; |
301 | | /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0)); |
302 | | /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59)); |
303 | | /// ``` |
304 | | #[inline] |
305 | 0 | pub const fn as_hms(self) -> (u8, u8, u8) { |
306 | 0 | (self.hour.get(), self.minute.get(), self.second.get()) |
307 | 0 | } |
308 | | |
309 | | /// Get the clock hour, minute, second, and millisecond. |
310 | | /// |
311 | | /// ```rust |
312 | | /// # use time_macros::time; |
313 | | /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0)); |
314 | | /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999)); |
315 | | /// ``` |
316 | | #[inline] |
317 | 0 | pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) { |
318 | 0 | ( |
319 | 0 | self.hour.get(), |
320 | 0 | self.minute.get(), |
321 | 0 | self.second.get(), |
322 | 0 | (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16, |
323 | 0 | ) |
324 | 0 | } |
325 | | |
326 | | /// Get the clock hour, minute, second, and microsecond. |
327 | | /// |
328 | | /// ```rust |
329 | | /// # use time_macros::time; |
330 | | /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0)); |
331 | | /// assert_eq!( |
332 | | /// time!(23:59:59.999_999).as_hms_micro(), |
333 | | /// (23, 59, 59, 999_999) |
334 | | /// ); |
335 | | /// ``` |
336 | | #[inline] |
337 | 0 | pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) { |
338 | 0 | ( |
339 | 0 | self.hour.get(), |
340 | 0 | self.minute.get(), |
341 | 0 | self.second.get(), |
342 | 0 | self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond), |
343 | 0 | ) |
344 | 0 | } |
345 | | |
346 | | /// Get the clock hour, minute, second, and nanosecond. |
347 | | /// |
348 | | /// ```rust |
349 | | /// # use time_macros::time; |
350 | | /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0)); |
351 | | /// assert_eq!( |
352 | | /// time!(23:59:59.999_999_999).as_hms_nano(), |
353 | | /// (23, 59, 59, 999_999_999) |
354 | | /// ); |
355 | | /// ``` |
356 | | #[inline] |
357 | 0 | pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) { |
358 | 0 | ( |
359 | 0 | self.hour.get(), |
360 | 0 | self.minute.get(), |
361 | 0 | self.second.get(), |
362 | 0 | self.nanosecond.get(), |
363 | 0 | ) |
364 | 0 | } |
365 | | |
366 | | /// Get the clock hour, minute, second, and nanosecond. |
367 | | #[cfg(feature = "quickcheck")] |
368 | | #[inline] |
369 | | pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) { |
370 | | (self.hour, self.minute, self.second, self.nanosecond) |
371 | | } |
372 | | |
373 | | /// Get the clock hour. |
374 | | /// |
375 | | /// The returned value will always be in the range `0..24`. |
376 | | /// |
377 | | /// ```rust |
378 | | /// # use time_macros::time; |
379 | | /// assert_eq!(time!(0:00:00).hour(), 0); |
380 | | /// assert_eq!(time!(23:59:59).hour(), 23); |
381 | | /// ``` |
382 | | #[inline] |
383 | 0 | pub const fn hour(self) -> u8 { |
384 | 0 | self.hour.get() |
385 | 0 | } Unexecuted instantiation: <time::time::Time>::hour Unexecuted instantiation: <time::time::Time>::hour |
386 | | |
387 | | /// Get the minute within the hour. |
388 | | /// |
389 | | /// The returned value will always be in the range `0..60`. |
390 | | /// |
391 | | /// ```rust |
392 | | /// # use time_macros::time; |
393 | | /// assert_eq!(time!(0:00:00).minute(), 0); |
394 | | /// assert_eq!(time!(23:59:59).minute(), 59); |
395 | | /// ``` |
396 | | #[inline] |
397 | 0 | pub const fn minute(self) -> u8 { |
398 | 0 | self.minute.get() |
399 | 0 | } Unexecuted instantiation: <time::time::Time>::minute Unexecuted instantiation: <time::time::Time>::minute |
400 | | |
401 | | /// Get the second within the minute. |
402 | | /// |
403 | | /// The returned value will always be in the range `0..60`. |
404 | | /// |
405 | | /// ```rust |
406 | | /// # use time_macros::time; |
407 | | /// assert_eq!(time!(0:00:00).second(), 0); |
408 | | /// assert_eq!(time!(23:59:59).second(), 59); |
409 | | /// ``` |
410 | | #[inline] |
411 | 0 | pub const fn second(self) -> u8 { |
412 | 0 | self.second.get() |
413 | 0 | } Unexecuted instantiation: <time::time::Time>::second Unexecuted instantiation: <time::time::Time>::second |
414 | | |
415 | | /// Get the milliseconds within the second. |
416 | | /// |
417 | | /// The returned value will always be in the range `0..1_000`. |
418 | | /// |
419 | | /// ```rust |
420 | | /// # use time_macros::time; |
421 | | /// assert_eq!(time!(0:00).millisecond(), 0); |
422 | | /// assert_eq!(time!(23:59:59.999).millisecond(), 999); |
423 | | /// ``` |
424 | | #[inline] |
425 | 0 | pub const fn millisecond(self) -> u16 { |
426 | 0 | (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16 |
427 | 0 | } |
428 | | |
429 | | /// Get the microseconds within the second. |
430 | | /// |
431 | | /// The returned value will always be in the range `0..1_000_000`. |
432 | | /// |
433 | | /// ```rust |
434 | | /// # use time_macros::time; |
435 | | /// assert_eq!(time!(0:00).microsecond(), 0); |
436 | | /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999); |
437 | | /// ``` |
438 | | #[inline] |
439 | 0 | pub const fn microsecond(self) -> u32 { |
440 | 0 | self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond) |
441 | 0 | } |
442 | | |
443 | | /// Get the nanoseconds within the second. |
444 | | /// |
445 | | /// The returned value will always be in the range `0..1_000_000_000`. |
446 | | /// |
447 | | /// ```rust |
448 | | /// # use time_macros::time; |
449 | | /// assert_eq!(time!(0:00).nanosecond(), 0); |
450 | | /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999); |
451 | | /// ``` |
452 | | #[inline] |
453 | 0 | pub const fn nanosecond(self) -> u32 { |
454 | 0 | self.nanosecond.get() |
455 | 0 | } |
456 | | |
457 | | /// Determine the [`Duration`] that, if added to `self`, would result in the parameter. |
458 | | /// |
459 | | /// ```rust |
460 | | /// # use time::Time; |
461 | | /// # use time::ext::NumericalDuration; |
462 | | /// # use time_macros::time; |
463 | | /// assert_eq!(time!(18:00).duration_until(Time::MIDNIGHT), 6.hours()); |
464 | | /// assert_eq!(time!(23:00).duration_until(time!(1:00)), 2.hours()); |
465 | | /// ``` |
466 | | #[inline] |
467 | 0 | pub const fn duration_until(self, other: Self) -> Duration { |
468 | 0 | let mut nanoseconds = other.nanosecond.get() as i32 - self.nanosecond.get() as i32; |
469 | 0 | let seconds = other.second.get() as i8 - self.second.get() as i8; |
470 | 0 | let minutes = other.minute.get() as i8 - self.minute.get() as i8; |
471 | 0 | let hours = other.hour.get() as i8 - self.hour.get() as i8; |
472 | | |
473 | | // Safety: For all four variables, the bounds are obviously true given the previous bounds |
474 | | // and nature of subtraction. |
475 | 0 | unsafe { |
476 | 0 | hint::assert_unchecked( |
477 | 0 | nanoseconds >= Nanoseconds::MIN.get() as i32 - Nanoseconds::MAX.get() as i32, |
478 | 0 | ); |
479 | 0 | hint::assert_unchecked( |
480 | 0 | nanoseconds <= Nanoseconds::MAX.get() as i32 - Nanoseconds::MIN.get() as i32, |
481 | 0 | ); |
482 | 0 | hint::assert_unchecked(seconds >= Seconds::MIN.get() as i8 - Seconds::MAX.get() as i8); |
483 | 0 | hint::assert_unchecked(seconds <= Seconds::MAX.get() as i8 - Seconds::MIN.get() as i8); |
484 | 0 | hint::assert_unchecked(minutes >= Minutes::MIN.get() as i8 - Minutes::MAX.get() as i8); |
485 | 0 | hint::assert_unchecked(minutes <= Minutes::MAX.get() as i8 - Minutes::MIN.get() as i8); |
486 | 0 | hint::assert_unchecked(hours >= Hours::MIN.get() as i8 - Hours::MAX.get() as i8); |
487 | 0 | hint::assert_unchecked(hours <= Hours::MAX.get() as i8 - Hours::MIN.get() as i8); |
488 | 0 | } |
489 | | |
490 | 0 | let mut total_seconds = hours as i32 * Second::per_t::<i32>(Hour) |
491 | 0 | + minutes as i32 * Second::per_t::<i32>(Minute) |
492 | 0 | + seconds as i32; |
493 | | |
494 | 0 | cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => total_seconds); |
495 | | |
496 | 0 | if total_seconds < 0 { |
497 | 0 | total_seconds += Second::per_t::<i32>(Day); |
498 | 0 | } |
499 | | |
500 | | // Safety: The range of `nanoseconds` is guaranteed by the cascades above. |
501 | 0 | unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) } |
502 | 0 | } |
503 | | |
504 | | /// Determine the [`Duration`] that, if added to the parameter, would result in `self`. |
505 | | /// |
506 | | /// ```rust |
507 | | /// # use time::Time; |
508 | | /// # use time::ext::NumericalDuration; |
509 | | /// # use time_macros::time; |
510 | | /// assert_eq!(Time::MIDNIGHT.duration_since(time!(18:00)), 6.hours()); |
511 | | /// assert_eq!(time!(1:00).duration_since(time!(23:00)), 2.hours()); |
512 | | /// ``` |
513 | | #[inline] |
514 | 0 | pub const fn duration_since(self, other: Self) -> Duration { |
515 | 0 | other.duration_until(self) |
516 | 0 | } |
517 | | |
518 | | /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether |
519 | | /// the date is different. |
520 | | #[inline] |
521 | 0 | pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) { |
522 | 0 | let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds(); |
523 | 0 | let mut seconds = self.second.get() as i8 |
524 | 0 | + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8; |
525 | 0 | let mut minutes = |
526 | 0 | self.minute.get() as i8 + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8; |
527 | 0 | let mut hours = |
528 | 0 | self.hour.get() as i8 + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8; |
529 | 0 | let mut date_adjustment = DateAdjustment::None; |
530 | | |
531 | 0 | cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds); |
532 | 0 | cascade!(seconds in 0..Second::per_t(Minute) => minutes); |
533 | 0 | cascade!(minutes in 0..Minute::per_t(Hour) => hours); |
534 | 0 | if hours >= Hour::per_t(Day) { |
535 | 0 | hours -= Hour::per_t::<i8>(Day); |
536 | 0 | date_adjustment = DateAdjustment::Next; |
537 | 0 | } else if hours < 0 { |
538 | 0 | hours += Hour::per_t::<i8>(Day); |
539 | 0 | date_adjustment = DateAdjustment::Previous; |
540 | 0 | } |
541 | | |
542 | 0 | ( |
543 | 0 | date_adjustment, |
544 | 0 | // Safety: The cascades above ensure the values are in range. |
545 | 0 | unsafe { |
546 | 0 | Self::__from_hms_nanos_unchecked( |
547 | 0 | hours as u8, |
548 | 0 | minutes as u8, |
549 | 0 | seconds as u8, |
550 | 0 | nanoseconds as u32, |
551 | 0 | ) |
552 | 0 | }, |
553 | 0 | ) |
554 | 0 | } |
555 | | |
556 | | /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning |
557 | | /// whether the date is different. |
558 | | #[inline] |
559 | 0 | pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) { |
560 | 0 | let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds(); |
561 | 0 | let mut seconds = self.second.get() as i8 |
562 | 0 | - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8; |
563 | 0 | let mut minutes = |
564 | 0 | self.minute.get() as i8 - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8; |
565 | 0 | let mut hours = |
566 | 0 | self.hour.get() as i8 - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8; |
567 | 0 | let mut date_adjustment = DateAdjustment::None; |
568 | | |
569 | 0 | cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds); |
570 | 0 | cascade!(seconds in 0..Second::per_t(Minute) => minutes); |
571 | 0 | cascade!(minutes in 0..Minute::per_t(Hour) => hours); |
572 | 0 | if hours >= Hour::per_t(Day) { |
573 | 0 | hours -= Hour::per_t::<i8>(Day); |
574 | 0 | date_adjustment = DateAdjustment::Next; |
575 | 0 | } else if hours < 0 { |
576 | 0 | hours += Hour::per_t::<i8>(Day); |
577 | 0 | date_adjustment = DateAdjustment::Previous; |
578 | 0 | } |
579 | | |
580 | 0 | ( |
581 | 0 | date_adjustment, |
582 | 0 | // Safety: The cascades above ensure the values are in range. |
583 | 0 | unsafe { |
584 | 0 | Self::__from_hms_nanos_unchecked( |
585 | 0 | hours as u8, |
586 | 0 | minutes as u8, |
587 | 0 | seconds as u8, |
588 | 0 | nanoseconds as u32, |
589 | 0 | ) |
590 | 0 | }, |
591 | 0 | ) |
592 | 0 | } |
593 | | |
594 | | /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow, |
595 | | /// returning whether the date is the previous date as the first element of the tuple. |
596 | | #[inline] |
597 | 0 | pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) { |
598 | 0 | let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos(); |
599 | 0 | let mut second = |
600 | 0 | self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8; |
601 | 0 | let mut minute = self.minute.get() |
602 | 0 | + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour)) |
603 | 0 | as u8; |
604 | 0 | let mut hour = self.hour.get() |
605 | 0 | + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8; |
606 | 0 | let mut is_next_day = false; |
607 | | |
608 | 0 | cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second); |
609 | 0 | cascade!(second in 0..Second::per_t(Minute) => minute); |
610 | 0 | cascade!(minute in 0..Minute::per_t(Hour) => hour); |
611 | 0 | if hour >= Hour::per_t::<u8>(Day) { |
612 | 0 | hour -= Hour::per_t::<u8>(Day); |
613 | 0 | is_next_day = true; |
614 | 0 | } |
615 | | |
616 | 0 | ( |
617 | 0 | is_next_day, |
618 | 0 | // Safety: The cascades above ensure the values are in range. |
619 | 0 | unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) }, |
620 | 0 | ) |
621 | 0 | } Unexecuted instantiation: <time::time::Time>::adjusting_add_std Unexecuted instantiation: <time::time::Time>::adjusting_add_std |
622 | | |
623 | | /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow, |
624 | | /// returning whether the date is the previous date as the first element of the tuple. |
625 | | #[inline] |
626 | 0 | pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) { |
627 | 0 | let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32; |
628 | 0 | let mut second = |
629 | 0 | self.second.get() as i8 - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8; |
630 | 0 | let mut minute = self.minute.get() as i8 |
631 | 0 | - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour)) |
632 | 0 | as i8; |
633 | 0 | let mut hour = self.hour.get() as i8 |
634 | 0 | - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8; |
635 | 0 | let mut is_previous_day = false; |
636 | | |
637 | 0 | cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second); |
638 | 0 | cascade!(second in 0..Second::per_t(Minute) => minute); |
639 | 0 | cascade!(minute in 0..Minute::per_t(Hour) => hour); |
640 | 0 | if hour < 0 { |
641 | 0 | hour += Hour::per_t::<i8>(Day); |
642 | 0 | is_previous_day = true; |
643 | 0 | } |
644 | | |
645 | 0 | ( |
646 | 0 | is_previous_day, |
647 | 0 | // Safety: The cascades above ensure the values are in range. |
648 | 0 | unsafe { |
649 | 0 | Self::__from_hms_nanos_unchecked( |
650 | 0 | hour as u8, |
651 | 0 | minute as u8, |
652 | 0 | second as u8, |
653 | 0 | nanosecond as u32, |
654 | 0 | ) |
655 | 0 | }, |
656 | 0 | ) |
657 | 0 | } |
658 | | |
659 | | /// Replace the clock hour. |
660 | | /// |
661 | | /// ```rust |
662 | | /// # use time_macros::time; |
663 | | /// assert_eq!( |
664 | | /// time!(01:02:03.004_005_006).replace_hour(7), |
665 | | /// Ok(time!(07:02:03.004_005_006)) |
666 | | /// ); |
667 | | /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour |
668 | | /// ``` |
669 | | #[must_use = "This method does not mutate the original `Time`."] |
670 | | #[inline] |
671 | 0 | pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> { |
672 | 0 | self.hour = ensure_ranged!(Hours: hour); |
673 | 0 | Ok(self) |
674 | 0 | } |
675 | | |
676 | | /// Replace the minutes within the hour. |
677 | | /// |
678 | | /// ```rust |
679 | | /// # use time_macros::time; |
680 | | /// assert_eq!( |
681 | | /// time!(01:02:03.004_005_006).replace_minute(7), |
682 | | /// Ok(time!(01:07:03.004_005_006)) |
683 | | /// ); |
684 | | /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute |
685 | | /// ``` |
686 | | #[must_use = "This method does not mutate the original `Time`."] |
687 | | #[inline] |
688 | 0 | pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> { |
689 | 0 | self.minute = ensure_ranged!(Minutes: minute); |
690 | 0 | Ok(self) |
691 | 0 | } |
692 | | |
693 | | /// Replace the seconds within the minute. |
694 | | /// |
695 | | /// ```rust |
696 | | /// # use time_macros::time; |
697 | | /// assert_eq!( |
698 | | /// time!(01:02:03.004_005_006).replace_second(7), |
699 | | /// Ok(time!(01:02:07.004_005_006)) |
700 | | /// ); |
701 | | /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second |
702 | | /// ``` |
703 | | #[must_use = "This method does not mutate the original `Time`."] |
704 | | #[inline] |
705 | 0 | pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> { |
706 | 0 | self.second = ensure_ranged!(Seconds: second); |
707 | 0 | Ok(self) |
708 | 0 | } |
709 | | |
710 | | /// Replace the milliseconds within the second. |
711 | | /// |
712 | | /// ```rust |
713 | | /// # use time_macros::time; |
714 | | /// assert_eq!( |
715 | | /// time!(01:02:03.004_005_006).replace_millisecond(7), |
716 | | /// Ok(time!(01:02:03.007)) |
717 | | /// ); |
718 | | /// assert!(time!(01:02:03.004_005_006) |
719 | | /// .replace_millisecond(1_000) |
720 | | /// .is_err()); // 1_000 isn't a valid millisecond |
721 | | /// ``` |
722 | | #[must_use = "This method does not mutate the original `Time`."] |
723 | | #[inline] |
724 | 0 | pub const fn replace_millisecond( |
725 | 0 | mut self, |
726 | 0 | millisecond: u16, |
727 | 0 | ) -> Result<Self, error::ComponentRange> { |
728 | | self.nanosecond = |
729 | 0 | ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)); |
730 | 0 | Ok(self) |
731 | 0 | } |
732 | | |
733 | | /// Replace the microseconds within the second. |
734 | | /// |
735 | | /// ```rust |
736 | | /// # use time_macros::time; |
737 | | /// assert_eq!( |
738 | | /// time!(01:02:03.004_005_006).replace_microsecond(7_008), |
739 | | /// Ok(time!(01:02:03.007_008)) |
740 | | /// ); |
741 | | /// assert!(time!(01:02:03.004_005_006) |
742 | | /// .replace_microsecond(1_000_000) |
743 | | /// .is_err()); // 1_000_000 isn't a valid microsecond |
744 | | /// ``` |
745 | | #[must_use = "This method does not mutate the original `Time`."] |
746 | | #[inline] |
747 | 0 | pub const fn replace_microsecond( |
748 | 0 | mut self, |
749 | 0 | microsecond: u32, |
750 | 0 | ) -> Result<Self, error::ComponentRange> { |
751 | | self.nanosecond = |
752 | 0 | ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)); |
753 | 0 | Ok(self) |
754 | 0 | } |
755 | | |
756 | | /// Replace the nanoseconds within the second. |
757 | | /// |
758 | | /// ```rust |
759 | | /// # use time_macros::time; |
760 | | /// assert_eq!( |
761 | | /// time!(01:02:03.004_005_006).replace_nanosecond(7_008_009), |
762 | | /// Ok(time!(01:02:03.007_008_009)) |
763 | | /// ); |
764 | | /// assert!(time!(01:02:03.004_005_006) |
765 | | /// .replace_nanosecond(1_000_000_000) |
766 | | /// .is_err()); // 1_000_000_000 isn't a valid nanosecond |
767 | | /// ``` |
768 | | #[must_use = "This method does not mutate the original `Time`."] |
769 | | #[inline] |
770 | 0 | pub const fn replace_nanosecond( |
771 | 0 | mut self, |
772 | 0 | nanosecond: u32, |
773 | 0 | ) -> Result<Self, error::ComponentRange> { |
774 | 0 | self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond); |
775 | 0 | Ok(self) |
776 | 0 | } |
777 | | } |
778 | | |
779 | | #[cfg(feature = "formatting")] |
780 | | impl Time { |
781 | | /// Format the `Time` using the provided [format description](crate::format_description). |
782 | | #[inline] |
783 | | pub fn format_into( |
784 | | self, |
785 | | output: &mut (impl io::Write + ?Sized), |
786 | | format: &(impl Formattable + ?Sized), |
787 | | ) -> Result<usize, error::Format> { |
788 | | format.format_into(output, None, Some(self), None) |
789 | | } |
790 | | |
791 | | /// Format the `Time` using the provided [format description](crate::format_description). |
792 | | /// |
793 | | /// ```rust |
794 | | /// # use time::format_description; |
795 | | /// # use time_macros::time; |
796 | | /// let format = format_description::parse("[hour]:[minute]:[second]")?; |
797 | | /// assert_eq!(time!(12:00).format(&format)?, "12:00:00"); |
798 | | /// # Ok::<_, time::Error>(()) |
799 | | /// ``` |
800 | | #[inline] |
801 | | pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> { |
802 | | format.format(None, Some(self), None) |
803 | | } |
804 | | } |
805 | | |
806 | | #[cfg(feature = "parsing")] |
807 | | impl Time { |
808 | | /// Parse a `Time` from the input using the provided [format |
809 | | /// description](crate::format_description). |
810 | | /// |
811 | | /// ```rust |
812 | | /// # use time::Time; |
813 | | /// # use time_macros::{time, format_description}; |
814 | | /// let format = format_description!("[hour]:[minute]:[second]"); |
815 | | /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00)); |
816 | | /// # Ok::<_, time::Error>(()) |
817 | | /// ``` |
818 | | #[inline] |
819 | | pub fn parse( |
820 | | input: &str, |
821 | | description: &(impl Parsable + ?Sized), |
822 | | ) -> Result<Self, error::Parse> { |
823 | | description.parse_time(input.as_bytes()) |
824 | | } |
825 | | } |
826 | | |
827 | | mod private { |
828 | | #[non_exhaustive] |
829 | | #[derive(Debug, Clone, Copy)] |
830 | | pub struct TimeMetadata { |
831 | | /// How many characters wide the formatted subsecond is. |
832 | | pub(super) subsecond_width: u8, |
833 | | /// The value to use when formatting the subsecond. Leading zeroes will be added as |
834 | | /// necessary. |
835 | | pub(super) subsecond_value: u32, |
836 | | } |
837 | | } |
838 | | use private::TimeMetadata; |
839 | | |
840 | | impl SmartDisplay for Time { |
841 | | type Metadata = TimeMetadata; |
842 | | |
843 | | #[inline] |
844 | 0 | fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { |
845 | 0 | let (subsecond_value, subsecond_width) = match self.nanosecond() { |
846 | 0 | nanos if nanos % 10 != 0 => (nanos, 9), |
847 | 0 | nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8), |
848 | 0 | nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7), |
849 | 0 | nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6), |
850 | 0 | nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5), |
851 | 0 | nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4), |
852 | 0 | nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3), |
853 | 0 | nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2), |
854 | 0 | nanos => (nanos / 100_000_000, 1), |
855 | | }; |
856 | | |
857 | 0 | let formatted_width = smart_display::padded_width_of!( |
858 | 0 | self.hour.get(), |
859 | 0 | ":", |
860 | 0 | self.minute.get() => width(2) fill('0'), |
861 | 0 | ":", |
862 | 0 | self.second.get() => width(2) fill('0'), |
863 | 0 | ".", |
864 | 0 | ) + subsecond_width; |
865 | | |
866 | 0 | Metadata::new( |
867 | 0 | formatted_width, |
868 | 0 | self, |
869 | 0 | TimeMetadata { |
870 | 0 | subsecond_width: subsecond_width.truncate(), |
871 | 0 | subsecond_value, |
872 | 0 | }, |
873 | | ) |
874 | 0 | } |
875 | | |
876 | | #[inline] |
877 | 0 | fn fmt_with_metadata( |
878 | 0 | &self, |
879 | 0 | f: &mut fmt::Formatter<'_>, |
880 | 0 | metadata: Metadata<Self>, |
881 | 0 | ) -> fmt::Result { |
882 | 0 | let subsecond_width = metadata.subsecond_width.extend(); |
883 | 0 | let subsecond_value = metadata.subsecond_value; |
884 | | |
885 | 0 | f.pad_with_width( |
886 | 0 | metadata.unpadded_width(), |
887 | 0 | format_args!( |
888 | 0 | "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}", |
889 | | self.hour, self.minute, self.second |
890 | | ), |
891 | | ) |
892 | 0 | } |
893 | | } |
894 | | |
895 | | impl fmt::Display for Time { |
896 | | #[inline] |
897 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
898 | 0 | SmartDisplay::fmt(self, f) |
899 | 0 | } |
900 | | } |
901 | | |
902 | | impl fmt::Debug for Time { |
903 | | #[inline] |
904 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
905 | 0 | fmt::Display::fmt(self, f) |
906 | 0 | } |
907 | | } |
908 | | |
909 | | impl Add<Duration> for Time { |
910 | | type Output = Self; |
911 | | |
912 | | /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow. |
913 | | /// |
914 | | /// ```rust |
915 | | /// # use time::ext::NumericalDuration; |
916 | | /// # use time_macros::time; |
917 | | /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00)); |
918 | | /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59)); |
919 | | /// ``` |
920 | | #[inline] |
921 | 0 | fn add(self, duration: Duration) -> Self::Output { |
922 | 0 | self.adjusting_add(duration).1 |
923 | 0 | } |
924 | | } |
925 | | |
926 | | impl Add<StdDuration> for Time { |
927 | | type Output = Self; |
928 | | |
929 | | /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow. |
930 | | /// |
931 | | /// ```rust |
932 | | /// # use time::ext::NumericalStdDuration; |
933 | | /// # use time_macros::time; |
934 | | /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00)); |
935 | | /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01)); |
936 | | /// ``` |
937 | | #[inline] |
938 | 0 | fn add(self, duration: StdDuration) -> Self::Output { |
939 | 0 | self.adjusting_add_std(duration).1 |
940 | 0 | } |
941 | | } |
942 | | |
943 | | impl_add_assign!(Time: Duration, StdDuration); |
944 | | |
945 | | impl Sub<Duration> for Time { |
946 | | type Output = Self; |
947 | | |
948 | | /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow. |
949 | | /// |
950 | | /// ```rust |
951 | | /// # use time::ext::NumericalDuration; |
952 | | /// # use time_macros::time; |
953 | | /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00)); |
954 | | /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01)); |
955 | | /// ``` |
956 | | #[inline] |
957 | 0 | fn sub(self, duration: Duration) -> Self::Output { |
958 | 0 | self.adjusting_sub(duration).1 |
959 | 0 | } |
960 | | } |
961 | | |
962 | | impl Sub<StdDuration> for Time { |
963 | | type Output = Self; |
964 | | |
965 | | /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow. |
966 | | /// |
967 | | /// ```rust |
968 | | /// # use time::ext::NumericalStdDuration; |
969 | | /// # use time_macros::time; |
970 | | /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00)); |
971 | | /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59)); |
972 | | /// ``` |
973 | | #[inline] |
974 | 0 | fn sub(self, duration: StdDuration) -> Self::Output { |
975 | 0 | self.adjusting_sub_std(duration).1 |
976 | 0 | } |
977 | | } |
978 | | |
979 | | impl_sub_assign!(Time: Duration, StdDuration); |
980 | | |
981 | | impl Sub for Time { |
982 | | type Output = Duration; |
983 | | |
984 | | /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in |
985 | | /// the same calendar day. |
986 | | /// |
987 | | /// ```rust |
988 | | /// # use time::ext::NumericalDuration; |
989 | | /// # use time_macros::time; |
990 | | /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds()); |
991 | | /// assert_eq!(time!(1:00) - time!(0:00), 1.hours()); |
992 | | /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours()); |
993 | | /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours()); |
994 | | /// ``` |
995 | | #[inline] |
996 | 0 | fn sub(self, rhs: Self) -> Self::Output { |
997 | 0 | let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed(); |
998 | 0 | let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed(); |
999 | 0 | let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed(); |
1000 | 0 | let nanosecond_diff = |
1001 | 0 | self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed(); |
1002 | | |
1003 | 0 | let seconds = hour_diff.extend::<i32>() * Second::per_t::<i32>(Hour) |
1004 | 0 | + minute_diff.extend::<i32>() * Second::per_t::<i32>(Minute) |
1005 | 0 | + second_diff.extend::<i32>(); |
1006 | | |
1007 | 0 | let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 { |
1008 | 0 | ( |
1009 | 0 | seconds - 1, |
1010 | 0 | nanosecond_diff + Nanosecond::per_t::<i32>(Second), |
1011 | 0 | ) |
1012 | 0 | } else if seconds < 0 && nanosecond_diff > 0 { |
1013 | 0 | ( |
1014 | 0 | seconds + 1, |
1015 | 0 | nanosecond_diff - Nanosecond::per_t::<i32>(Second), |
1016 | 0 | ) |
1017 | | } else { |
1018 | 0 | (seconds, nanosecond_diff) |
1019 | | }; |
1020 | | |
1021 | | // Safety: `nanoseconds` is in range due to the overflow handling. |
1022 | 0 | unsafe { Duration::new_unchecked(seconds.extend(), nanoseconds) } |
1023 | 0 | } |
1024 | | } |