1#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::cmp::Ordering;
6use core::hash::{Hash, Hasher};
7use core::mem::MaybeUninit;
8use core::ops::{Add, AddAssign, Sub, SubAssign};
9use core::time::Duration as StdDuration;
10use core::{fmt, hint};
11#[cfg(feature = "formatting")]
12use std::io;
13
14use deranged::{ru8, ru32};
15use num_conv::prelude::*;
16use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
17
18#[cfg(feature = "formatting")]
19use crate::formatting::Formattable;
20use crate::internal_macros::{cascade, ensure_ranged};
21use crate::num_fmt::{
22 one_to_two_digits_no_padding, str_from_raw_parts, truncated_subsecond_from_nanos,
23 two_digits_zero_padded,
24};
25#[cfg(feature = "parsing")]
26use crate::parsing::Parsable;
27use crate::unit::*;
28use crate::util::DateAdjustment;
29use crate::{Duration, error};
30
31#[repr(u8)]
34#[derive(#[automatically_derived]
impl ::core::clone::Clone for Padding {
#[inline]
fn clone(&self) -> Padding { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Padding { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for Padding {
#[inline]
fn eq(&self, other: &Padding) -> bool { true }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Padding {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for Padding {
#[inline]
fn partial_cmp(&self, other: &Padding)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ordering::Equal)
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for Padding {
#[inline]
fn cmp(&self, other: &Padding) -> ::core::cmp::Ordering {
::core::cmp::Ordering::Equal
}
}Ord, #[automatically_derived]
impl ::core::hash::Hash for Padding {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {}
}Hash)]
35pub(crate) enum Padding {
36 #[allow(clippy::missing_docs_in_private_items)]
37 Optimize,
38}
39
40pub(crate) type Hours = ru8<0, { Hour::per_t::<u8>(Day) - 1 }>;
42pub(crate) type Minutes = ru8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
44pub(crate) type Seconds = ru8<0, { Second::per_t::<u8>(Minute) - 1 }>;
46pub(crate) type Nanoseconds = ru32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>;
48
49#[derive(#[automatically_derived]
impl ::core::clone::Clone for Time {
#[inline]
fn clone(&self) -> Time {
let _: ::core::clone::AssertParamIsClone<Nanoseconds>;
let _: ::core::clone::AssertParamIsClone<Seconds>;
let _: ::core::clone::AssertParamIsClone<Minutes>;
let _: ::core::clone::AssertParamIsClone<Hours>;
let _: ::core::clone::AssertParamIsClone<Padding>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Time { }Copy, #[automatically_derived]
impl ::core::cmp::Eq for Time {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Nanoseconds>;
let _: ::core::cmp::AssertParamIsEq<Seconds>;
let _: ::core::cmp::AssertParamIsEq<Minutes>;
let _: ::core::cmp::AssertParamIsEq<Hours>;
let _: ::core::cmp::AssertParamIsEq<Padding>;
}
}Eq)]
56#[cfg_attr(not(docsrs), repr(C))]
57pub struct Time {
58 #[cfg(target_endian = "little")]
62 nanosecond: Nanoseconds,
63 #[cfg(target_endian = "little")]
64 second: Seconds,
65 #[cfg(target_endian = "little")]
66 minute: Minutes,
67 #[cfg(target_endian = "little")]
68 hour: Hours,
69 #[cfg(target_endian = "little")]
70 padding: Padding,
71
72 #[cfg(target_endian = "big")]
74 padding: Padding,
75 #[cfg(target_endian = "big")]
76 hour: Hours,
77 #[cfg(target_endian = "big")]
78 minute: Minutes,
79 #[cfg(target_endian = "big")]
80 second: Seconds,
81 #[cfg(target_endian = "big")]
82 nanosecond: Nanoseconds,
83}
84
85impl Hash for Time {
86 #[inline]
87 fn hash<H>(&self, state: &mut H)
88 where
89 H: Hasher,
90 {
91 self.as_u64().hash(state)
92 }
93}
94
95impl PartialEq for Time {
96 #[inline]
97 fn eq(&self, other: &Self) -> bool {
98 self.as_u64().eq(&other.as_u64())
99 }
100}
101
102impl PartialOrd for Time {
103 #[inline]
104 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
105 Some(self.cmp(other))
106 }
107}
108
109impl Ord for Time {
110 #[inline]
111 fn cmp(&self, other: &Self) -> Ordering {
112 self.as_u64().cmp(&other.as_u64())
113 }
114}
115
116impl Time {
117 #[inline]
120 pub(crate) const fn as_u64(self) -> u64 {
121 unsafe { core::mem::transmute(self) }
125 }
126
127 #[doc(alias = "MIN")]
135 pub const MIDNIGHT: Self =
136 Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
137
138 pub const MAX: Self =
147 Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
148
149 #[doc(hidden)]
158 #[inline]
159 #[track_caller]
160 pub const unsafe fn __from_hms_nanos_unchecked(
161 hour: u8,
162 minute: u8,
163 second: u8,
164 nanosecond: u32,
165 ) -> Self {
166 unsafe {
168 Self::from_hms_nanos_ranged(
169 Hours::new_unchecked(hour),
170 Minutes::new_unchecked(minute),
171 Seconds::new_unchecked(second),
172 Nanoseconds::new_unchecked(nanosecond),
173 )
174 }
175 }
176
177 #[inline]
191 pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
192 Ok(Self::from_hms_nanos_ranged(
193 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
194 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
195 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
196 Nanoseconds::MIN,
197 ))
198 }
199
200 #[inline]
202 pub(crate) const fn from_hms_nanos_ranged(
203 hour: Hours,
204 minute: Minutes,
205 second: Seconds,
206 nanosecond: Nanoseconds,
207 ) -> Self {
208 Self {
209 hour,
210 minute,
211 second,
212 nanosecond,
213 padding: Padding::Optimize,
214 }
215 }
216
217 #[inline]
232 pub const fn from_hms_milli(
233 hour: u8,
234 minute: u8,
235 second: u8,
236 millisecond: u16,
237 ) -> Result<Self, error::ComponentRange> {
238 Ok(Self::from_hms_nanos_ranged(
239 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
240 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
241 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
242 match (millisecond as u32).checked_mul(Nanosecond::per_t::<u32>(Millisecond))
{
Some(val) =>
match <Nanoseconds>::new(val) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("millisecond"));
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("millisecond"));
}
}ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)),
243 ))
244 }
245
246 #[inline]
261 pub const fn from_hms_micro(
262 hour: u8,
263 minute: u8,
264 second: u8,
265 microsecond: u32,
266 ) -> Result<Self, error::ComponentRange> {
267 Ok(Self::from_hms_nanos_ranged(
268 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
269 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
270 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
271 match (microsecond).checked_mul(Nanosecond::per_t::<u32>(Microsecond)) {
Some(val) =>
match <Nanoseconds>::new(val) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("microsecond"));
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("microsecond"));
}
}ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)),
272 ))
273 }
274
275 #[inline]
290 pub const fn from_hms_nano(
291 hour: u8,
292 minute: u8,
293 second: u8,
294 nanosecond: u32,
295 ) -> Result<Self, error::ComponentRange> {
296 Ok(Self::from_hms_nanos_ranged(
297 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
298 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
299 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
300 match <Nanoseconds>::new(nanosecond) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("nanosecond"));
}
}ensure_ranged!(Nanoseconds: nanosecond),
301 ))
302 }
303
304 #[inline]
312 pub const fn as_hms(self) -> (u8, u8, u8) {
313 (self.hour.get(), self.minute.get(), self.second.get())
314 }
315
316 #[inline]
324 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
325 (
326 self.hour.get(),
327 self.minute.get(),
328 self.second.get(),
329 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16,
330 )
331 }
332
333 #[inline]
344 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
345 (
346 self.hour.get(),
347 self.minute.get(),
348 self.second.get(),
349 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
350 )
351 }
352
353 #[inline]
364 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
365 (
366 self.hour.get(),
367 self.minute.get(),
368 self.second.get(),
369 self.nanosecond.get(),
370 )
371 }
372
373 #[inline]
375 #[cfg(any(feature = "formatting", feature = "quickcheck"))]
376 pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
377 (self.hour, self.minute, self.second, self.nanosecond)
378 }
379
380 #[inline]
390 pub const fn hour(self) -> u8 {
391 self.hour.get()
392 }
393
394 #[inline]
404 pub const fn minute(self) -> u8 {
405 self.minute.get()
406 }
407
408 #[inline]
418 pub const fn second(self) -> u8 {
419 self.second.get()
420 }
421
422 #[inline]
432 pub const fn millisecond(self) -> u16 {
433 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
434 }
435
436 #[inline]
446 pub const fn microsecond(self) -> u32 {
447 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
448 }
449
450 #[inline]
460 pub const fn nanosecond(self) -> u32 {
461 self.nanosecond.get()
462 }
463
464 #[inline]
474 pub const fn duration_until(self, other: Self) -> Duration {
475 let mut nanoseconds =
476 other.nanosecond.get().cast_signed() - self.nanosecond.get().cast_signed();
477 let seconds = other.second.get().cast_signed() - self.second.get().cast_signed();
478 let minutes = other.minute.get().cast_signed() - self.minute.get().cast_signed();
479 let hours = other.hour.get().cast_signed() - self.hour.get().cast_signed();
480
481 unsafe {
484 hint::assert_unchecked(
485 nanoseconds
486 >= Nanoseconds::MIN.get().cast_signed() - Nanoseconds::MAX.get().cast_signed(),
487 );
488 hint::assert_unchecked(
489 nanoseconds
490 <= Nanoseconds::MAX.get().cast_signed() - Nanoseconds::MIN.get().cast_signed(),
491 );
492 hint::assert_unchecked(
493 seconds >= Seconds::MIN.get().cast_signed() - Seconds::MAX.get().cast_signed(),
494 );
495 hint::assert_unchecked(
496 seconds <= Seconds::MAX.get().cast_signed() - Seconds::MIN.get().cast_signed(),
497 );
498 hint::assert_unchecked(
499 minutes >= Minutes::MIN.get().cast_signed() - Minutes::MAX.get().cast_signed(),
500 );
501 hint::assert_unchecked(
502 minutes <= Minutes::MAX.get().cast_signed() - Minutes::MIN.get().cast_signed(),
503 );
504 hint::assert_unchecked(
505 hours >= Hours::MIN.get().cast_signed() - Hours::MAX.get().cast_signed(),
506 );
507 hint::assert_unchecked(
508 hours <= Hours::MAX.get().cast_signed() - Hours::MIN.get().cast_signed(),
509 );
510 }
511
512 let mut total_seconds = hours as i32 * Second::per_t::<i32>(Hour)
513 + minutes as i32 * Second::per_t::<i32>(Minute)
514 + seconds as i32;
515
516 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Nanosecond::per_t(Second);
if crate::hint::unlikely(nanoseconds >= max) {
nanoseconds -= max - min;
total_seconds += 1;
} else if crate::hint::unlikely(nanoseconds < min) {
nanoseconds += max - min;
total_seconds -= 1;
};cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => total_seconds);
517
518 if total_seconds < 0 {
519 total_seconds += Second::per_t::<i32>(Day);
520 }
521
522 unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) }
524 }
525
526 #[inline]
536 pub const fn duration_since(self, other: Self) -> Duration {
537 other.duration_until(self)
538 }
539
540 #[inline]
543 pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
544 let mut nanoseconds = self.nanosecond.get().cast_signed() + duration.subsec_nanoseconds();
545 let mut seconds = self.second.get().cast_signed()
546 + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
547 let mut minutes = self.minute.get().cast_signed()
548 + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
549 let mut hours = self.hour.get().cast_signed()
550 + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
551 let mut date_adjustment = DateAdjustment::None;
552
553 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Nanosecond::per_t(Second);
if crate::hint::unlikely(nanoseconds >= max) {
nanoseconds -= max - min;
seconds += 1;
} else if crate::hint::unlikely(nanoseconds < min) {
nanoseconds += max - min;
seconds -= 1;
};cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
554 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Second::per_t(Minute);
if crate::hint::unlikely(seconds >= max) {
seconds -= max - min;
minutes += 1;
} else if crate::hint::unlikely(seconds < min) {
seconds += max - min;
minutes -= 1;
};cascade!(seconds in 0..Second::per_t(Minute) => minutes);
555 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Minute::per_t(Hour);
if crate::hint::unlikely(minutes >= max) {
minutes -= max - min;
hours += 1;
} else if crate::hint::unlikely(minutes < min) {
minutes += max - min;
hours -= 1;
};cascade!(minutes in 0..Minute::per_t(Hour) => hours);
556 if hours >= Hour::per_t(Day) {
557 hours -= Hour::per_t::<i8>(Day);
558 date_adjustment = DateAdjustment::Next;
559 } else if hours < 0 {
560 hours += Hour::per_t::<i8>(Day);
561 date_adjustment = DateAdjustment::Previous;
562 }
563
564 (
565 date_adjustment,
566 unsafe {
568 Self::__from_hms_nanos_unchecked(
569 hours.cast_unsigned(),
570 minutes.cast_unsigned(),
571 seconds.cast_unsigned(),
572 nanoseconds.cast_unsigned(),
573 )
574 },
575 )
576 }
577
578 #[inline]
581 pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
582 let mut nanoseconds = self.nanosecond.get().cast_signed() - duration.subsec_nanoseconds();
583 let mut seconds = self.second.get().cast_signed()
584 - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
585 let mut minutes = self.minute.get().cast_signed()
586 - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
587 let mut hours = self.hour.get().cast_signed()
588 - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
589 let mut date_adjustment = DateAdjustment::None;
590
591 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Nanosecond::per_t(Second);
if crate::hint::unlikely(nanoseconds >= max) {
nanoseconds -= max - min;
seconds += 1;
} else if crate::hint::unlikely(nanoseconds < min) {
nanoseconds += max - min;
seconds -= 1;
};cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
592 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Second::per_t(Minute);
if crate::hint::unlikely(seconds >= max) {
seconds -= max - min;
minutes += 1;
} else if crate::hint::unlikely(seconds < min) {
seconds += max - min;
minutes -= 1;
};cascade!(seconds in 0..Second::per_t(Minute) => minutes);
593 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Minute::per_t(Hour);
if crate::hint::unlikely(minutes >= max) {
minutes -= max - min;
hours += 1;
} else if crate::hint::unlikely(minutes < min) {
minutes += max - min;
hours -= 1;
};cascade!(minutes in 0..Minute::per_t(Hour) => hours);
594 if hours >= Hour::per_t(Day) {
595 hours -= Hour::per_t::<i8>(Day);
596 date_adjustment = DateAdjustment::Next;
597 } else if hours < 0 {
598 hours += Hour::per_t::<i8>(Day);
599 date_adjustment = DateAdjustment::Previous;
600 }
601
602 (
603 date_adjustment,
604 unsafe {
606 Self::__from_hms_nanos_unchecked(
607 hours.cast_unsigned(),
608 minutes.cast_unsigned(),
609 seconds.cast_unsigned(),
610 nanoseconds.cast_unsigned(),
611 )
612 },
613 )
614 }
615
616 #[inline]
619 pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
620 let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
621 let mut second =
622 self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
623 let mut minute = self.minute.get()
624 + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
625 as u8;
626 let mut hour = self.hour.get()
627 + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
628 let mut is_next_day = false;
629
630 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Nanosecond::per_t(Second);
if crate::hint::unlikely(nanosecond >= max) {
nanosecond -= max - min;
second += 1;
} else if crate::hint::unlikely(nanosecond < min) {
nanosecond += max - min;
second -= 1;
};cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
631 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Second::per_t(Minute);
if crate::hint::unlikely(second >= max) {
second -= max - min;
minute += 1;
} else if crate::hint::unlikely(second < min) {
second += max - min;
minute -= 1;
};cascade!(second in 0..Second::per_t(Minute) => minute);
632 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Minute::per_t(Hour);
if crate::hint::unlikely(minute >= max) {
minute -= max - min;
hour += 1;
} else if crate::hint::unlikely(minute < min) {
minute += max - min;
hour -= 1;
};cascade!(minute in 0..Minute::per_t(Hour) => hour);
633 if hour >= Hour::per_t::<u8>(Day) {
634 hour -= Hour::per_t::<u8>(Day);
635 is_next_day = true;
636 }
637
638 (
639 is_next_day,
640 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
642 )
643 }
644
645 #[inline]
648 pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
649 let mut nanosecond =
650 self.nanosecond.get().cast_signed() - duration.subsec_nanos().cast_signed();
651 let mut second = self.second.get().cast_signed()
652 - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
653 let mut minute = self.minute.get().cast_signed()
654 - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
655 as i8;
656 let mut hour = self.hour.get().cast_signed()
657 - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
658 let mut is_previous_day = false;
659
660 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Nanosecond::per_t(Second);
if crate::hint::unlikely(nanosecond >= max) {
nanosecond -= max - min;
second += 1;
} else if crate::hint::unlikely(nanosecond < min) {
nanosecond += max - min;
second -= 1;
};cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
661 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Second::per_t(Minute);
if crate::hint::unlikely(second >= max) {
second -= max - min;
minute += 1;
} else if crate::hint::unlikely(second < min) {
second += max - min;
minute -= 1;
};cascade!(second in 0..Second::per_t(Minute) => minute);
662 #[allow(unused_comparisons, unused_assignments)]
let min = 0;
let max = Minute::per_t(Hour);
if crate::hint::unlikely(minute >= max) {
minute -= max - min;
hour += 1;
} else if crate::hint::unlikely(minute < min) {
minute += max - min;
hour -= 1;
};cascade!(minute in 0..Minute::per_t(Hour) => hour);
663 if hour < 0 {
664 hour += Hour::per_t::<i8>(Day);
665 is_previous_day = true;
666 }
667
668 (
669 is_previous_day,
670 unsafe {
672 Self::__from_hms_nanos_unchecked(
673 hour.cast_unsigned(),
674 minute.cast_unsigned(),
675 second.cast_unsigned(),
676 nanosecond.cast_unsigned(),
677 )
678 },
679 )
680 }
681
682 #[must_use = "This method does not mutate the original `Time`."]
693 #[inline]
694 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
695 self.hour = match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour);
696 Ok(self)
697 }
698
699 #[must_use = "This method does not mutate the original `Time`."]
706 #[inline]
707 pub const fn truncate_to_hour(mut self) -> Self {
708 self.minute = Minutes::MIN;
709 self.second = Seconds::MIN;
710 self.nanosecond = Nanoseconds::MIN;
711 self
712 }
713
714 #[must_use = "This method does not mutate the original `Time`."]
725 #[inline]
726 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
727 self.minute = match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute);
728 Ok(self)
729 }
730
731 #[must_use = "This method does not mutate the original `Time`."]
741 #[inline]
742 pub const fn truncate_to_minute(mut self) -> Self {
743 self.second = Seconds::MIN;
744 self.nanosecond = Nanoseconds::MIN;
745 self
746 }
747
748 #[must_use = "This method does not mutate the original `Time`."]
759 #[inline]
760 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
761 self.second = match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second);
762 Ok(self)
763 }
764
765 #[must_use = "This method does not mutate the original `Time`."]
775 #[inline]
776 pub const fn truncate_to_second(mut self) -> Self {
777 self.nanosecond = Nanoseconds::MIN;
778 self
779 }
780
781 #[must_use = "This method does not mutate the original `Time`."]
796 #[inline]
797 pub const fn replace_millisecond(
798 mut self,
799 millisecond: u16,
800 ) -> Result<Self, error::ComponentRange> {
801 self.nanosecond =
802 match (millisecond as u32).checked_mul(Nanosecond::per_t::<u32>(Millisecond))
{
Some(val) =>
match <Nanoseconds>::new(val) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("millisecond"));
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("millisecond"));
}
}ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
803 Ok(self)
804 }
805
806 #[must_use = "This method does not mutate the original `Time`."]
817 #[inline]
818 pub const fn truncate_to_millisecond(mut self) -> Self {
819 self.nanosecond = unsafe {
821 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000_000))
822 };
823 self
824 }
825
826 #[must_use = "This method does not mutate the original `Time`."]
841 #[inline]
842 pub const fn replace_microsecond(
843 mut self,
844 microsecond: u32,
845 ) -> Result<Self, error::ComponentRange> {
846 self.nanosecond =
847 match (microsecond).checked_mul(Nanosecond::per_t::<u32>(Microsecond)) {
Some(val) =>
match <Nanoseconds>::new(val) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("microsecond"));
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("microsecond"));
}
}ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
848 Ok(self)
849 }
850
851 #[must_use = "This method does not mutate the original `Time`."]
861 #[inline]
862 pub const fn truncate_to_microsecond(mut self) -> Self {
863 self.nanosecond = unsafe {
865 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000))
866 };
867 self
868 }
869
870 #[must_use = "This method does not mutate the original `Time`."]
885 #[inline]
886 pub const fn replace_nanosecond(
887 mut self,
888 nanosecond: u32,
889 ) -> Result<Self, error::ComponentRange> {
890 self.nanosecond = match <Nanoseconds>::new(nanosecond) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("nanosecond"));
}
}ensure_ranged!(Nanoseconds: nanosecond);
891 Ok(self)
892 }
893}
894
895#[cfg(feature = "formatting")]
896impl Time {
897 #[inline]
899 pub fn format_into(
900 self,
901 output: &mut (impl io::Write + ?Sized),
902 format: &(impl Formattable + ?Sized),
903 ) -> Result<usize, error::Format> {
904 format.format_into(output, &self, &mut Default::default())
905 }
906
907 #[inline]
917 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
918 format.format(&self, &mut Default::default())
919 }
920}
921
922#[cfg(feature = "parsing")]
923impl Time {
924 #[inline]
935 pub fn parse(
936 input: &str,
937 description: &(impl Parsable + ?Sized),
938 ) -> Result<Self, error::Parse> {
939 description.parse_time(input.as_bytes())
940 }
941}
942
943mod private {
944 #[non_exhaustive]
946 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for TimeMetadata {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "TimeMetadata")
}
}Debug)]
947 pub struct TimeMetadata;
948}
949use private::TimeMetadata;
950
951impl SmartDisplay for Time {
955 type Metadata = TimeMetadata;
956
957 #[inline]
958 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
959 let hour_width = if self.hour() < 10 { 1 } else { 2 };
960 let subsecond_width = match self.nanosecond() {
961 nanos if nanos % 10 != 0 => 9,
962 nanos if (nanos / 10) % 10 != 0 => 8,
963 nanos if (nanos / 100) % 10 != 0 => 7,
964 nanos if (nanos / 1_000) % 10 != 0 => 6,
965 nanos if (nanos / 10_000) % 10 != 0 => 5,
966 nanos if (nanos / 100_000) % 10 != 0 => 4,
967 nanos if (nanos / 1_000_000) % 10 != 0 => 3,
968 nanos if (nanos / 10_000_000) % 10 != 0 => 2,
969 _ => 1,
970 };
971 let total_width = hour_width + subsecond_width + 7;
972
973 Metadata::new(total_width, self, TimeMetadata)
974 }
975
976 #[inline]
977 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
978 fmt::Display::fmt(self, f)
979 }
980}
981
982impl Time {
983 pub(crate) const DISPLAY_BUFFER_SIZE: usize = 18;
986
987 #[inline]
989 pub(crate) fn fmt_into_buffer(
990 self,
991 buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
992 ) -> usize {
993 let mut idx = 0;
994
995 let hour =
997 one_to_two_digits_no_padding(unsafe { Hours::new_unchecked(self.hour()) }.expand());
998 unsafe {
1004 hour.as_ptr()
1005 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), hour.len())
1006 };
1007 idx += hour.len();
1008
1009 buf[idx] = MaybeUninit::new(b':');
1010 idx += 1;
1011
1012 unsafe {
1014 two_digits_zero_padded(Minutes::new_unchecked(self.minute()).expand())
1015 .as_ptr()
1016 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2)
1017 };
1018 idx += 2;
1019
1020 buf[idx] = MaybeUninit::new(b':');
1021 idx += 1;
1022
1023 unsafe {
1025 two_digits_zero_padded(Seconds::new_unchecked(self.second()).expand())
1026 .as_ptr()
1027 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2)
1028 };
1029 idx += 2;
1030
1031 buf[idx] = MaybeUninit::new(b'.');
1032 idx += 1;
1033
1034 let subsecond = truncated_subsecond_from_nanos(unsafe {
1036 Nanoseconds::new_unchecked(self.nanosecond())
1037 });
1038 unsafe {
1040 subsecond
1041 .as_ptr()
1042 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len())
1043 };
1044 idx += subsecond.len();
1045
1046 idx
1047 }
1048}
1049
1050impl fmt::Display for Time {
1051 #[inline]
1052 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1053 let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1054 let len = self.fmt_into_buffer(&mut buf);
1055 let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1057 f.pad(s)
1058 }
1059}
1060
1061impl fmt::Debug for Time {
1062 #[inline]
1063 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1064 fmt::Display::fmt(self, f)
1065 }
1066}
1067
1068impl Add<Duration> for Time {
1069 type Output = Self;
1070
1071 #[inline]
1080 fn add(self, duration: Duration) -> Self::Output {
1081 self.adjusting_add(duration).1
1082 }
1083}
1084
1085impl AddAssign<Duration> for Time {
1086 #[inline]
1087 fn add_assign(&mut self, rhs: Duration) {
1088 *self = *self + rhs;
1089 }
1090}
1091
1092impl Add<StdDuration> for Time {
1093 type Output = Self;
1094
1095 #[inline]
1104 fn add(self, duration: StdDuration) -> Self::Output {
1105 self.adjusting_add_std(duration).1
1106 }
1107}
1108
1109impl AddAssign<StdDuration> for Time {
1110 #[inline]
1111 fn add_assign(&mut self, rhs: StdDuration) {
1112 *self = *self + rhs;
1113 }
1114}
1115
1116impl Sub<Duration> for Time {
1117 type Output = Self;
1118
1119 #[inline]
1128 fn sub(self, duration: Duration) -> Self::Output {
1129 self.adjusting_sub(duration).1
1130 }
1131}
1132
1133impl SubAssign<Duration> for Time {
1134 #[inline]
1135 fn sub_assign(&mut self, rhs: Duration) {
1136 *self = *self - rhs;
1137 }
1138}
1139
1140impl Sub<StdDuration> for Time {
1141 type Output = Self;
1142
1143 #[inline]
1152 fn sub(self, duration: StdDuration) -> Self::Output {
1153 self.adjusting_sub_std(duration).1
1154 }
1155}
1156
1157impl SubAssign<StdDuration> for Time {
1158 #[inline]
1159 fn sub_assign(&mut self, rhs: StdDuration) {
1160 *self = *self - rhs;
1161 }
1162}
1163
1164impl Sub for Time {
1165 type Output = Duration;
1166
1167 #[inline]
1179 fn sub(self, rhs: Self) -> Self::Output {
1180 let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
1181 let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
1182 let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
1183 let nanosecond_diff =
1184 self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
1185
1186 let seconds = hour_diff.widen::<i32>() * Second::per_t::<i32>(Hour)
1187 + minute_diff.widen::<i32>() * Second::per_t::<i32>(Minute)
1188 + second_diff.widen::<i32>();
1189
1190 let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
1191 (
1192 seconds - 1,
1193 nanosecond_diff + Nanosecond::per_t::<i32>(Second),
1194 )
1195 } else if seconds < 0 && nanosecond_diff > 0 {
1196 (
1197 seconds + 1,
1198 nanosecond_diff - Nanosecond::per_t::<i32>(Second),
1199 )
1200 } else {
1201 (seconds, nanosecond_diff)
1202 };
1203
1204 unsafe { Duration::new_unchecked(seconds.widen(), nanoseconds) }
1206 }
1207}