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