time/time.rs
1//! The [`Time`] struct and its associated `impl`s.
2
3#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::cmp::Ordering;
6use core::hash::{Hash, Hasher};
7use core::ops::{Add, Sub};
8use core::time::Duration as StdDuration;
9use core::{fmt, hint};
10#[cfg(feature = "formatting")]
11use std::io;
12
13use deranged::{RangedU32, RangedU8};
14use num_conv::prelude::*;
15use powerfmt::ext::FormatterExt;
16use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
17
18use crate::convert::*;
19#[cfg(feature = "formatting")]
20use crate::formatting::Formattable;
21use crate::internal_macros::{cascade, ensure_ranged, impl_add_assign, impl_sub_assign};
22#[cfg(feature = "parsing")]
23use crate::parsing::Parsable;
24use crate::util::DateAdjustment;
25use 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)]
31pub(crate) enum Padding {
32 #[allow(clippy::missing_docs_in_private_items)]
33 Optimize,
34}
35
36/// The type of the `hour` field of `Time`.
37type Hours = RangedU8<0, { Hour::per_t::<u8>(Day) - 1 }>;
38/// The type of the `minute` field of `Time`.
39type Minutes = RangedU8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
40/// The type of the `second` field of `Time`.
41type Seconds = RangedU8<0, { Second::per_t::<u8>(Minute) - 1 }>;
42/// The type of the `nanosecond` field of `Time`.
43type 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))]
53pub 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
81impl Hash for Time {
82 #[inline]
83 fn hash<H: Hasher>(&self, state: &mut H) {
84 self.as_u64().hash(state)
85 }
86}
87
88impl PartialEq for Time {
89 #[inline]
90 fn eq(&self, other: &Self) -> bool {
91 self.as_u64().eq(&other.as_u64())
92 }
93}
94
95impl PartialOrd for Time {
96 #[inline]
97 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
98 Some(self.cmp(other))
99 }
100}
101
102impl Ord for Time {
103 #[inline]
104 fn cmp(&self, other: &Self) -> Ordering {
105 self.as_u64().cmp(&other.as_u64())
106 }
107}
108
109impl Time {
110 /// Provide a representation of `Time` as a `u64`. This value can be used for equality, hashing,
111 /// and ordering.
112 #[inline]
113 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 unsafe { core::mem::transmute(self) }
118 }
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 pub const unsafe fn __from_hms_nanos_unchecked(
154 hour: u8,
155 minute: u8,
156 second: u8,
157 nanosecond: u32,
158 ) -> Self {
159 // Safety: The caller must uphold the safety invariants.
160 unsafe {
161 Self::from_hms_nanos_ranged(
162 Hours::new_unchecked(hour),
163 Minutes::new_unchecked(minute),
164 Seconds::new_unchecked(second),
165 Nanoseconds::new_unchecked(nanosecond),
166 )
167 }
168 }
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 pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
185 Ok(Self::from_hms_nanos_ranged(
186 ensure_ranged!(Hours: hour),
187 ensure_ranged!(Minutes: minute),
188 ensure_ranged!(Seconds: second),
189 Nanoseconds::MIN,
190 ))
191 }
192
193 /// Create a `Time` from the hour, minute, second, and nanosecond.
194 #[inline]
195 pub(crate) const fn from_hms_nanos_ranged(
196 hour: Hours,
197 minute: Minutes,
198 second: Seconds,
199 nanosecond: Nanoseconds,
200 ) -> Self {
201 Self {
202 hour,
203 minute,
204 second,
205 nanosecond,
206 padding: Padding::Optimize,
207 }
208 }
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 pub const fn from_hms_milli(
226 hour: u8,
227 minute: u8,
228 second: u8,
229 millisecond: u16,
230 ) -> Result<Self, error::ComponentRange> {
231 Ok(Self::from_hms_nanos_ranged(
232 ensure_ranged!(Hours: hour),
233 ensure_ranged!(Minutes: minute),
234 ensure_ranged!(Seconds: second),
235 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)),
236 ))
237 }
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 pub const fn from_hms_micro(
255 hour: u8,
256 minute: u8,
257 second: u8,
258 microsecond: u32,
259 ) -> Result<Self, error::ComponentRange> {
260 Ok(Self::from_hms_nanos_ranged(
261 ensure_ranged!(Hours: hour),
262 ensure_ranged!(Minutes: minute),
263 ensure_ranged!(Seconds: second),
264 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)),
265 ))
266 }
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 pub const fn from_hms_nano(
284 hour: u8,
285 minute: u8,
286 second: u8,
287 nanosecond: u32,
288 ) -> Result<Self, error::ComponentRange> {
289 Ok(Self::from_hms_nanos_ranged(
290 ensure_ranged!(Hours: hour),
291 ensure_ranged!(Minutes: minute),
292 ensure_ranged!(Seconds: second),
293 ensure_ranged!(Nanoseconds: nanosecond),
294 ))
295 }
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 pub const fn as_hms(self) -> (u8, u8, u8) {
306 (self.hour.get(), self.minute.get(), self.second.get())
307 }
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 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
318 (
319 self.hour.get(),
320 self.minute.get(),
321 self.second.get(),
322 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16,
323 )
324 }
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 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
338 (
339 self.hour.get(),
340 self.minute.get(),
341 self.second.get(),
342 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
343 )
344 }
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 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
358 (
359 self.hour.get(),
360 self.minute.get(),
361 self.second.get(),
362 self.nanosecond.get(),
363 )
364 }
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 pub const fn hour(self) -> u8 {
384 self.hour.get()
385 }
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 pub const fn minute(self) -> u8 {
398 self.minute.get()
399 }
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 pub const fn second(self) -> u8 {
412 self.second.get()
413 }
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 pub const fn millisecond(self) -> u16 {
426 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
427 }
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 pub const fn microsecond(self) -> u32 {
440 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
441 }
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 pub const fn nanosecond(self) -> u32 {
454 self.nanosecond.get()
455 }
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 pub const fn duration_until(self, other: Self) -> Duration {
468 let mut nanoseconds = other.nanosecond.get() as i32 - self.nanosecond.get() as i32;
469 let seconds = other.second.get() as i8 - self.second.get() as i8;
470 let minutes = other.minute.get() as i8 - self.minute.get() as i8;
471 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 unsafe {
476 hint::assert_unchecked(
477 nanoseconds >= Nanoseconds::MIN.get() as i32 - Nanoseconds::MAX.get() as i32,
478 );
479 hint::assert_unchecked(
480 nanoseconds <= Nanoseconds::MAX.get() as i32 - Nanoseconds::MIN.get() as i32,
481 );
482 hint::assert_unchecked(seconds >= Seconds::MIN.get() as i8 - Seconds::MAX.get() as i8);
483 hint::assert_unchecked(seconds <= Seconds::MAX.get() as i8 - Seconds::MIN.get() as i8);
484 hint::assert_unchecked(minutes >= Minutes::MIN.get() as i8 - Minutes::MAX.get() as i8);
485 hint::assert_unchecked(minutes <= Minutes::MAX.get() as i8 - Minutes::MIN.get() as i8);
486 hint::assert_unchecked(hours >= Hours::MIN.get() as i8 - Hours::MAX.get() as i8);
487 hint::assert_unchecked(hours <= Hours::MAX.get() as i8 - Hours::MIN.get() as i8);
488 }
489
490 let mut total_seconds = hours as i32 * Second::per_t::<i32>(Hour)
491 + minutes as i32 * Second::per_t::<i32>(Minute)
492 + seconds as i32;
493
494 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => total_seconds);
495
496 if total_seconds < 0 {
497 total_seconds += Second::per_t::<i32>(Day);
498 }
499
500 // Safety: The range of `nanoseconds` is guaranteed by the cascades above.
501 unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) }
502 }
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 pub const fn duration_since(self, other: Self) -> Duration {
515 other.duration_until(self)
516 }
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 pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
522 let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds();
523 let mut seconds = self.second.get() as i8
524 + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
525 let mut minutes =
526 self.minute.get() as i8 + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
527 let mut hours =
528 self.hour.get() as i8 + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
529 let mut date_adjustment = DateAdjustment::None;
530
531 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
532 cascade!(seconds in 0..Second::per_t(Minute) => minutes);
533 cascade!(minutes in 0..Minute::per_t(Hour) => hours);
534 if hours >= Hour::per_t(Day) {
535 hours -= Hour::per_t::<i8>(Day);
536 date_adjustment = DateAdjustment::Next;
537 } else if hours < 0 {
538 hours += Hour::per_t::<i8>(Day);
539 date_adjustment = DateAdjustment::Previous;
540 }
541
542 (
543 date_adjustment,
544 // Safety: The cascades above ensure the values are in range.
545 unsafe {
546 Self::__from_hms_nanos_unchecked(
547 hours as u8,
548 minutes as u8,
549 seconds as u8,
550 nanoseconds as u32,
551 )
552 },
553 )
554 }
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 pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
560 let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
561 let mut seconds = self.second.get() as i8
562 - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
563 let mut minutes =
564 self.minute.get() as i8 - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
565 let mut hours =
566 self.hour.get() as i8 - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
567 let mut date_adjustment = DateAdjustment::None;
568
569 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
570 cascade!(seconds in 0..Second::per_t(Minute) => minutes);
571 cascade!(minutes in 0..Minute::per_t(Hour) => hours);
572 if hours >= Hour::per_t(Day) {
573 hours -= Hour::per_t::<i8>(Day);
574 date_adjustment = DateAdjustment::Next;
575 } else if hours < 0 {
576 hours += Hour::per_t::<i8>(Day);
577 date_adjustment = DateAdjustment::Previous;
578 }
579
580 (
581 date_adjustment,
582 // Safety: The cascades above ensure the values are in range.
583 unsafe {
584 Self::__from_hms_nanos_unchecked(
585 hours as u8,
586 minutes as u8,
587 seconds as u8,
588 nanoseconds as u32,
589 )
590 },
591 )
592 }
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 pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
598 let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
599 let mut second =
600 self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
601 let mut minute = self.minute.get()
602 + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
603 as u8;
604 let mut hour = self.hour.get()
605 + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
606 let mut is_next_day = false;
607
608 cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
609 cascade!(second in 0..Second::per_t(Minute) => minute);
610 cascade!(minute in 0..Minute::per_t(Hour) => hour);
611 if hour >= Hour::per_t::<u8>(Day) {
612 hour -= Hour::per_t::<u8>(Day);
613 is_next_day = true;
614 }
615
616 (
617 is_next_day,
618 // Safety: The cascades above ensure the values are in range.
619 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
620 )
621 }
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 pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
627 let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
628 let mut second =
629 self.second.get() as i8 - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
630 let mut minute = self.minute.get() as i8
631 - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
632 as i8;
633 let mut hour = self.hour.get() as i8
634 - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
635 let mut is_previous_day = false;
636
637 cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
638 cascade!(second in 0..Second::per_t(Minute) => minute);
639 cascade!(minute in 0..Minute::per_t(Hour) => hour);
640 if hour < 0 {
641 hour += Hour::per_t::<i8>(Day);
642 is_previous_day = true;
643 }
644
645 (
646 is_previous_day,
647 // Safety: The cascades above ensure the values are in range.
648 unsafe {
649 Self::__from_hms_nanos_unchecked(
650 hour as u8,
651 minute as u8,
652 second as u8,
653 nanosecond as u32,
654 )
655 },
656 )
657 }
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 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
672 self.hour = ensure_ranged!(Hours: hour);
673 Ok(self)
674 }
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 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
689 self.minute = ensure_ranged!(Minutes: minute);
690 Ok(self)
691 }
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 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
706 self.second = ensure_ranged!(Seconds: second);
707 Ok(self)
708 }
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 pub const fn replace_millisecond(
725 mut self,
726 millisecond: u16,
727 ) -> Result<Self, error::ComponentRange> {
728 self.nanosecond =
729 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
730 Ok(self)
731 }
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 pub const fn replace_microsecond(
748 mut self,
749 microsecond: u32,
750 ) -> Result<Self, error::ComponentRange> {
751 self.nanosecond =
752 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
753 Ok(self)
754 }
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 pub const fn replace_nanosecond(
771 mut self,
772 nanosecond: u32,
773 ) -> Result<Self, error::ComponentRange> {
774 self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
775 Ok(self)
776 }
777}
778
779#[cfg(feature = "formatting")]
780impl 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")]
807impl 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
827mod 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}
838use private::TimeMetadata;
839
840impl SmartDisplay for Time {
841 type Metadata = TimeMetadata;
842
843 #[inline]
844 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
845 let (subsecond_value, subsecond_width) = match self.nanosecond() {
846 nanos if nanos % 10 != 0 => (nanos, 9),
847 nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
848 nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
849 nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
850 nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
851 nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
852 nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
853 nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
854 nanos => (nanos / 100_000_000, 1),
855 };
856
857 let formatted_width = smart_display::padded_width_of!(
858 self.hour.get(),
859 ":",
860 self.minute.get() => width(2) fill('0'),
861 ":",
862 self.second.get() => width(2) fill('0'),
863 ".",
864 ) + subsecond_width;
865
866 Metadata::new(
867 formatted_width,
868 self,
869 TimeMetadata {
870 subsecond_width: subsecond_width.truncate(),
871 subsecond_value,
872 },
873 )
874 }
875
876 #[inline]
877 fn fmt_with_metadata(
878 &self,
879 f: &mut fmt::Formatter<'_>,
880 metadata: Metadata<Self>,
881 ) -> fmt::Result {
882 let subsecond_width = metadata.subsecond_width.extend();
883 let subsecond_value = metadata.subsecond_value;
884
885 f.pad_with_width(
886 metadata.unpadded_width(),
887 format_args!(
888 "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
889 self.hour, self.minute, self.second
890 ),
891 )
892 }
893}
894
895impl fmt::Display for Time {
896 #[inline]
897 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
898 SmartDisplay::fmt(self, f)
899 }
900}
901
902impl fmt::Debug for Time {
903 #[inline]
904 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
905 fmt::Display::fmt(self, f)
906 }
907}
908
909impl 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 fn add(self, duration: Duration) -> Self::Output {
922 self.adjusting_add(duration).1
923 }
924}
925
926impl 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 fn add(self, duration: StdDuration) -> Self::Output {
939 self.adjusting_add_std(duration).1
940 }
941}
942
943impl_add_assign!(Time: Duration, StdDuration);
944
945impl 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 fn sub(self, duration: Duration) -> Self::Output {
958 self.adjusting_sub(duration).1
959 }
960}
961
962impl 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 fn sub(self, duration: StdDuration) -> Self::Output {
975 self.adjusting_sub_std(duration).1
976 }
977}
978
979impl_sub_assign!(Time: Duration, StdDuration);
980
981impl 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 fn sub(self, rhs: Self) -> Self::Output {
997 let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
998 let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
999 let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
1000 let nanosecond_diff =
1001 self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
1002
1003 let seconds = hour_diff.extend::<i32>() * Second::per_t::<i32>(Hour)
1004 + minute_diff.extend::<i32>() * Second::per_t::<i32>(Minute)
1005 + second_diff.extend::<i32>();
1006
1007 let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
1008 (
1009 seconds - 1,
1010 nanosecond_diff + Nanosecond::per_t::<i32>(Second),
1011 )
1012 } else if seconds < 0 && nanosecond_diff > 0 {
1013 (
1014 seconds + 1,
1015 nanosecond_diff - Nanosecond::per_t::<i32>(Second),
1016 )
1017 } else {
1018 (seconds, nanosecond_diff)
1019 };
1020
1021 // Safety: `nanoseconds` is in range due to the overflow handling.
1022 unsafe { Duration::new_unchecked(seconds.extend(), nanoseconds) }
1023 }
1024}