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(any(feature = "formatting", feature = "parsing"))]
19use crate::PrivateMethod;
20#[cfg(feature = "formatting")]
21use crate::formatting::Formattable;
22use crate::internal_macros::{cascade, ensure_ranged};
23use crate::num_fmt::{
24 one_to_two_digits_no_padding, str_from_raw_parts, truncated_subsecond_from_nanos,
25 two_digits_zero_padded,
26};
27#[cfg(feature = "parsing")]
28use crate::parsing::{Parsable, Parsed};
29use crate::unit::*;
30use crate::util::DateAdjustment;
31use crate::{Duration, error};
32
33#[repr(u8)]
36#[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)]
37pub(crate) enum Padding {
38 #[allow(clippy::missing_docs_in_private_items)]
39 Optimize,
40}
41
42pub(crate) type Hours = ru8<0, { Hour::per_t::<u8>(Day) - 1 }>;
44pub(crate) type Minutes = ru8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
46pub(crate) type Seconds = ru8<0, { Second::per_t::<u8>(Minute) - 1 }>;
48pub(crate) type Nanoseconds = ru32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>;
50
51#[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)]
58#[cfg_attr(not(docsrs), repr(C))]
59pub struct Time {
60 #[cfg(target_endian = "little")]
64 nanosecond: Nanoseconds,
65 #[cfg(target_endian = "little")]
66 second: Seconds,
67 #[cfg(target_endian = "little")]
68 minute: Minutes,
69 #[cfg(target_endian = "little")]
70 hour: Hours,
71 #[cfg(target_endian = "little")]
72 padding: Padding,
73
74 #[cfg(target_endian = "big")]
76 padding: Padding,
77 #[cfg(target_endian = "big")]
78 hour: Hours,
79 #[cfg(target_endian = "big")]
80 minute: Minutes,
81 #[cfg(target_endian = "big")]
82 second: Seconds,
83 #[cfg(target_endian = "big")]
84 nanosecond: Nanoseconds,
85}
86
87impl Hash for Time {
88 #[inline]
89 fn hash<H>(&self, state: &mut H)
90 where
91 H: Hasher,
92 {
93 self.as_u64().hash(state)
94 }
95}
96
97impl PartialEq for Time {
98 #[inline]
99 fn eq(&self, other: &Self) -> bool {
100 self.as_u64().eq(&other.as_u64())
101 }
102}
103
104impl PartialOrd for Time {
105 #[inline]
106 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
107 Some(self.cmp(other))
108 }
109}
110
111impl Ord for Time {
112 #[inline]
113 fn cmp(&self, other: &Self) -> Ordering {
114 self.as_u64().cmp(&other.as_u64())
115 }
116}
117
118impl Time {
119 #[inline]
122 pub(crate) const fn as_u64(self) -> u64 {
123 unsafe { core::mem::transmute(self) }
127 }
128
129 #[doc(alias = "MIN")]
137 pub const MIDNIGHT: Self =
138 Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
139
140 pub const MAX: Self =
149 Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
150
151 #[doc(hidden)]
160 #[inline]
161 #[track_caller]
162 pub const unsafe fn __from_hms_nanos_unchecked(
163 hour: u8,
164 minute: u8,
165 second: u8,
166 nanosecond: u32,
167 ) -> Self {
168 unsafe {
170 Self::from_hms_nanos_ranged(
171 Hours::new_unchecked(hour),
172 Minutes::new_unchecked(minute),
173 Seconds::new_unchecked(second),
174 Nanoseconds::new_unchecked(nanosecond),
175 )
176 }
177 }
178
179 #[inline]
193 pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
194 Ok(Self::from_hms_nanos_ranged(
195 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
196 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
197 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
198 Nanoseconds::MIN,
199 ))
200 }
201
202 #[inline]
204 pub(crate) const fn from_hms_nanos_ranged(
205 hour: Hours,
206 minute: Minutes,
207 second: Seconds,
208 nanosecond: Nanoseconds,
209 ) -> Self {
210 Self {
211 hour,
212 minute,
213 second,
214 nanosecond,
215 padding: Padding::Optimize,
216 }
217 }
218
219 #[inline]
234 pub const fn from_hms_milli(
235 hour: u8,
236 minute: u8,
237 second: u8,
238 millisecond: u16,
239 ) -> Result<Self, error::ComponentRange> {
240 Ok(Self::from_hms_nanos_ranged(
241 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
242 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
243 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
244 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)),
245 ))
246 }
247
248 #[inline]
263 pub const fn from_hms_micro(
264 hour: u8,
265 minute: u8,
266 second: u8,
267 microsecond: u32,
268 ) -> Result<Self, error::ComponentRange> {
269 Ok(Self::from_hms_nanos_ranged(
270 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
271 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
272 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
273 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)),
274 ))
275 }
276
277 #[inline]
292 pub const fn from_hms_nano(
293 hour: u8,
294 minute: u8,
295 second: u8,
296 nanosecond: u32,
297 ) -> Result<Self, error::ComponentRange> {
298 Ok(Self::from_hms_nanos_ranged(
299 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
300 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
301 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
302 match <Nanoseconds>::new(nanosecond) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("nanosecond"));
}
}ensure_ranged!(Nanoseconds: nanosecond),
303 ))
304 }
305
306 #[inline]
314 pub const fn as_hms(self) -> (u8, u8, u8) {
315 (self.hour.get(), self.minute.get(), self.second.get())
316 }
317
318 #[inline]
326 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
327 (
328 self.hour.get(),
329 self.minute.get(),
330 self.second.get(),
331 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16,
332 )
333 }
334
335 #[inline]
346 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
347 (
348 self.hour.get(),
349 self.minute.get(),
350 self.second.get(),
351 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
352 )
353 }
354
355 #[inline]
366 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
367 (
368 self.hour.get(),
369 self.minute.get(),
370 self.second.get(),
371 self.nanosecond.get(),
372 )
373 }
374
375 #[inline]
377 #[cfg(any(feature = "formatting", feature = "quickcheck"))]
378 pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
379 (self.hour, self.minute, self.second, self.nanosecond)
380 }
381
382 #[inline]
392 pub const fn hour(self) -> u8 {
393 self.hour.get()
394 }
395
396 #[inline]
406 pub const fn minute(self) -> u8 {
407 self.minute.get()
408 }
409
410 #[inline]
420 pub const fn second(self) -> u8 {
421 self.second.get()
422 }
423
424 #[inline]
434 pub const fn millisecond(self) -> u16 {
435 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
436 }
437
438 #[inline]
448 pub const fn microsecond(self) -> u32 {
449 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
450 }
451
452 #[inline]
462 pub const fn nanosecond(self) -> u32 {
463 self.nanosecond.get()
464 }
465
466 #[inline]
476 pub const fn duration_until(self, other: Self) -> Duration {
477 let mut nanoseconds =
478 other.nanosecond.get().cast_signed() - self.nanosecond.get().cast_signed();
479 let seconds = other.second.get().cast_signed() - self.second.get().cast_signed();
480 let minutes = other.minute.get().cast_signed() - self.minute.get().cast_signed();
481 let hours = other.hour.get().cast_signed() - self.hour.get().cast_signed();
482
483 unsafe {
486 hint::assert_unchecked(
487 nanoseconds
488 >= Nanoseconds::MIN.get().cast_signed() - Nanoseconds::MAX.get().cast_signed(),
489 );
490 hint::assert_unchecked(
491 nanoseconds
492 <= Nanoseconds::MAX.get().cast_signed() - Nanoseconds::MIN.get().cast_signed(),
493 );
494 hint::assert_unchecked(
495 seconds >= Seconds::MIN.get().cast_signed() - Seconds::MAX.get().cast_signed(),
496 );
497 hint::assert_unchecked(
498 seconds <= Seconds::MAX.get().cast_signed() - Seconds::MIN.get().cast_signed(),
499 );
500 hint::assert_unchecked(
501 minutes >= Minutes::MIN.get().cast_signed() - Minutes::MAX.get().cast_signed(),
502 );
503 hint::assert_unchecked(
504 minutes <= Minutes::MAX.get().cast_signed() - Minutes::MIN.get().cast_signed(),
505 );
506 hint::assert_unchecked(
507 hours >= Hours::MIN.get().cast_signed() - Hours::MAX.get().cast_signed(),
508 );
509 hint::assert_unchecked(
510 hours <= Hours::MAX.get().cast_signed() - Hours::MIN.get().cast_signed(),
511 );
512 }
513
514 let mut total_seconds = hours as i32 * Second::per_t::<i32>(Hour)
515 + minutes as i32 * Second::per_t::<i32>(Minute)
516 + seconds as i32;
517
518 #[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);
519
520 if total_seconds < 0 {
521 total_seconds += Second::per_t::<i32>(Day);
522 }
523
524 unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) }
526 }
527
528 #[inline]
538 pub const fn duration_since(self, other: Self) -> Duration {
539 other.duration_until(self)
540 }
541
542 #[inline]
545 pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
546 let mut nanoseconds = self.nanosecond.get().cast_signed() + duration.subsec_nanoseconds();
547 let mut seconds = self.second.get().cast_signed()
548 + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
549 let mut minutes = self.minute.get().cast_signed()
550 + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
551 let mut hours = self.hour.get().cast_signed()
552 + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
553 let mut date_adjustment = DateAdjustment::None;
554
555 #[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);
556 #[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);
557 #[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);
558 if hours >= Hour::per_t(Day) {
559 hours -= Hour::per_t::<i8>(Day);
560 date_adjustment = DateAdjustment::Next;
561 } else if hours < 0 {
562 hours += Hour::per_t::<i8>(Day);
563 date_adjustment = DateAdjustment::Previous;
564 }
565
566 (
567 date_adjustment,
568 unsafe {
570 Self::__from_hms_nanos_unchecked(
571 hours.cast_unsigned(),
572 minutes.cast_unsigned(),
573 seconds.cast_unsigned(),
574 nanoseconds.cast_unsigned(),
575 )
576 },
577 )
578 }
579
580 #[inline]
583 pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
584 let mut nanoseconds = self.nanosecond.get().cast_signed() - duration.subsec_nanoseconds();
585 let mut seconds = self.second.get().cast_signed()
586 - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
587 let mut minutes = self.minute.get().cast_signed()
588 - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
589 let mut hours = self.hour.get().cast_signed()
590 - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
591 let mut date_adjustment = DateAdjustment::None;
592
593 #[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);
594 #[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);
595 #[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);
596 if hours >= Hour::per_t(Day) {
597 hours -= Hour::per_t::<i8>(Day);
598 date_adjustment = DateAdjustment::Next;
599 } else if hours < 0 {
600 hours += Hour::per_t::<i8>(Day);
601 date_adjustment = DateAdjustment::Previous;
602 }
603
604 (
605 date_adjustment,
606 unsafe {
608 Self::__from_hms_nanos_unchecked(
609 hours.cast_unsigned(),
610 minutes.cast_unsigned(),
611 seconds.cast_unsigned(),
612 nanoseconds.cast_unsigned(),
613 )
614 },
615 )
616 }
617
618 #[inline]
621 pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
622 let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
623 let mut second =
624 self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
625 let mut minute = self.minute.get()
626 + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
627 as u8;
628 let mut hour = self.hour.get()
629 + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
630 let mut is_next_day = false;
631
632 #[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);
633 #[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);
634 #[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);
635 if hour >= Hour::per_t::<u8>(Day) {
636 hour -= Hour::per_t::<u8>(Day);
637 is_next_day = true;
638 }
639
640 (
641 is_next_day,
642 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
644 )
645 }
646
647 #[inline]
650 pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
651 let mut nanosecond =
652 self.nanosecond.get().cast_signed() - duration.subsec_nanos().cast_signed();
653 let mut second = self.second.get().cast_signed()
654 - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
655 let mut minute = self.minute.get().cast_signed()
656 - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
657 as i8;
658 let mut hour = self.hour.get().cast_signed()
659 - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
660 let mut is_previous_day = false;
661
662 #[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);
663 #[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);
664 #[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);
665 if hour < 0 {
666 hour += Hour::per_t::<i8>(Day);
667 is_previous_day = true;
668 }
669
670 (
671 is_previous_day,
672 unsafe {
674 Self::__from_hms_nanos_unchecked(
675 hour.cast_unsigned(),
676 minute.cast_unsigned(),
677 second.cast_unsigned(),
678 nanosecond.cast_unsigned(),
679 )
680 },
681 )
682 }
683
684 #[must_use = "This method does not mutate the original `Time`."]
695 #[inline]
696 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
697 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);
698 Ok(self)
699 }
700
701 #[must_use = "This method does not mutate the original `Time`."]
708 #[inline]
709 pub const fn truncate_to_hour(mut self) -> Self {
710 self.minute = Minutes::MIN;
711 self.second = Seconds::MIN;
712 self.nanosecond = Nanoseconds::MIN;
713 self
714 }
715
716 #[must_use = "This method does not mutate the original `Time`."]
727 #[inline]
728 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
729 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);
730 Ok(self)
731 }
732
733 #[must_use = "This method does not mutate the original `Time`."]
743 #[inline]
744 pub const fn truncate_to_minute(mut self) -> Self {
745 self.second = Seconds::MIN;
746 self.nanosecond = Nanoseconds::MIN;
747 self
748 }
749
750 #[must_use = "This method does not mutate the original `Time`."]
761 #[inline]
762 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
763 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);
764 Ok(self)
765 }
766
767 #[must_use = "This method does not mutate the original `Time`."]
777 #[inline]
778 pub const fn truncate_to_second(mut self) -> Self {
779 self.nanosecond = Nanoseconds::MIN;
780 self
781 }
782
783 #[must_use = "This method does not mutate the original `Time`."]
798 #[inline]
799 pub const fn replace_millisecond(
800 mut self,
801 millisecond: u16,
802 ) -> Result<Self, error::ComponentRange> {
803 self.nanosecond =
804 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));
805 Ok(self)
806 }
807
808 #[must_use = "This method does not mutate the original `Time`."]
819 #[inline]
820 pub const fn truncate_to_millisecond(mut self) -> Self {
821 self.nanosecond = unsafe {
823 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000_000))
824 };
825 self
826 }
827
828 #[must_use = "This method does not mutate the original `Time`."]
843 #[inline]
844 pub const fn replace_microsecond(
845 mut self,
846 microsecond: u32,
847 ) -> Result<Self, error::ComponentRange> {
848 self.nanosecond =
849 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));
850 Ok(self)
851 }
852
853 #[must_use = "This method does not mutate the original `Time`."]
863 #[inline]
864 pub const fn truncate_to_microsecond(mut self) -> Self {
865 self.nanosecond = unsafe {
867 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000))
868 };
869 self
870 }
871
872 #[must_use = "This method does not mutate the original `Time`."]
887 #[inline]
888 pub const fn replace_nanosecond(
889 mut self,
890 nanosecond: u32,
891 ) -> Result<Self, error::ComponentRange> {
892 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);
893 Ok(self)
894 }
895}
896
897#[cfg(feature = "formatting")]
898impl Time {
899 #[inline]
901 pub fn format_into(
902 self,
903 output: &mut (impl io::Write + ?Sized),
904 format: &(impl Formattable + ?Sized),
905 ) -> Result<usize, error::Format> {
906 format.format_into(output, &self, &mut Default::default(), PrivateMethod)
907 }
908
909 #[inline]
919 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
920 format.format(&self, &mut Default::default(), PrivateMethod)
921 }
922}
923
924#[cfg(feature = "parsing")]
925impl Time {
926 #[inline]
937 pub fn parse(
938 input: &str,
939 description: &(impl Parsable + ?Sized),
940 ) -> Result<Self, error::Parse> {
941 description.parse_time(input.as_bytes(), None, PrivateMethod)
942 }
943
944 #[inline]
960 pub fn parse_with_defaults(
961 input: &[u8],
962 description: &(impl Parsable + ?Sized),
963 defaults: Parsed,
964 ) -> Result<Self, error::Parse> {
965 description.parse_time(input, Some(defaults), PrivateMethod)
966 }
967}
968
969mod private {
970 #[non_exhaustive]
972 #[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)]
973 pub struct TimeMetadata;
974}
975use private::TimeMetadata;
976
977impl SmartDisplay for Time {
981 type Metadata = TimeMetadata;
982
983 #[inline]
984 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
985 let hour_width = if self.hour() < 10 { 1 } else { 2 };
986 let subsecond_width = match self.nanosecond() {
987 nanos if nanos % 10 != 0 => 9,
988 nanos if (nanos / 10) % 10 != 0 => 8,
989 nanos if (nanos / 100) % 10 != 0 => 7,
990 nanos if (nanos / 1_000) % 10 != 0 => 6,
991 nanos if (nanos / 10_000) % 10 != 0 => 5,
992 nanos if (nanos / 100_000) % 10 != 0 => 4,
993 nanos if (nanos / 1_000_000) % 10 != 0 => 3,
994 nanos if (nanos / 10_000_000) % 10 != 0 => 2,
995 _ => 1,
996 };
997 let total_width = hour_width + subsecond_width + 7;
998
999 Metadata::new(total_width, self, TimeMetadata)
1000 }
1001
1002 #[inline]
1003 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1004 fmt::Display::fmt(self, f)
1005 }
1006}
1007
1008impl Time {
1009 pub(crate) const DISPLAY_BUFFER_SIZE: usize = 18;
1012
1013 #[inline]
1015 pub(crate) fn fmt_into_buffer(
1016 self,
1017 buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1018 ) -> usize {
1019 let mut idx = 0;
1020
1021 let hour =
1023 one_to_two_digits_no_padding(unsafe { Hours::new_unchecked(self.hour()) }.expand());
1024 unsafe {
1030 hour.as_ptr()
1031 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), hour.len())
1032 };
1033 idx += hour.len();
1034
1035 buf[idx] = MaybeUninit::new(b':');
1036 idx += 1;
1037
1038 unsafe {
1040 two_digits_zero_padded(Minutes::new_unchecked(self.minute()).expand())
1041 .as_ptr()
1042 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2)
1043 };
1044 idx += 2;
1045
1046 buf[idx] = MaybeUninit::new(b':');
1047 idx += 1;
1048
1049 unsafe {
1051 two_digits_zero_padded(Seconds::new_unchecked(self.second()).expand())
1052 .as_ptr()
1053 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2)
1054 };
1055 idx += 2;
1056
1057 buf[idx] = MaybeUninit::new(b'.');
1058 idx += 1;
1059
1060 let subsecond = truncated_subsecond_from_nanos(unsafe {
1062 Nanoseconds::new_unchecked(self.nanosecond())
1063 });
1064 unsafe {
1066 subsecond
1067 .as_ptr()
1068 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len())
1069 };
1070 idx += subsecond.len();
1071
1072 idx
1073 }
1074}
1075
1076impl fmt::Display for Time {
1077 #[inline]
1078 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1079 let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1080 let len = self.fmt_into_buffer(&mut buf);
1081 let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1083 f.pad(s)
1084 }
1085}
1086
1087impl fmt::Debug for Time {
1088 #[inline]
1089 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1090 fmt::Display::fmt(self, f)
1091 }
1092}
1093
1094impl Add<Duration> for Time {
1095 type Output = Self;
1096
1097 #[inline]
1106 fn add(self, duration: Duration) -> Self::Output {
1107 self.adjusting_add(duration).1
1108 }
1109}
1110
1111impl AddAssign<Duration> for Time {
1112 #[inline]
1113 fn add_assign(&mut self, rhs: Duration) {
1114 *self = *self + rhs;
1115 }
1116}
1117
1118impl Add<StdDuration> for Time {
1119 type Output = Self;
1120
1121 #[inline]
1130 fn add(self, duration: StdDuration) -> Self::Output {
1131 self.adjusting_add_std(duration).1
1132 }
1133}
1134
1135impl AddAssign<StdDuration> for Time {
1136 #[inline]
1137 fn add_assign(&mut self, rhs: StdDuration) {
1138 *self = *self + rhs;
1139 }
1140}
1141
1142impl Sub<Duration> for Time {
1143 type Output = Self;
1144
1145 #[inline]
1154 fn sub(self, duration: Duration) -> Self::Output {
1155 self.adjusting_sub(duration).1
1156 }
1157}
1158
1159impl SubAssign<Duration> for Time {
1160 #[inline]
1161 fn sub_assign(&mut self, rhs: Duration) {
1162 *self = *self - rhs;
1163 }
1164}
1165
1166impl Sub<StdDuration> for Time {
1167 type Output = Self;
1168
1169 #[inline]
1178 fn sub(self, duration: StdDuration) -> Self::Output {
1179 self.adjusting_sub_std(duration).1
1180 }
1181}
1182
1183impl SubAssign<StdDuration> for Time {
1184 #[inline]
1185 fn sub_assign(&mut self, rhs: StdDuration) {
1186 *self = *self - rhs;
1187 }
1188}
1189
1190impl Sub for Time {
1191 type Output = Duration;
1192
1193 #[inline]
1205 fn sub(self, rhs: Self) -> Self::Output {
1206 let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
1207 let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
1208 let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
1209 let nanosecond_diff =
1210 self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
1211
1212 let seconds = hour_diff.widen::<i32>() * Second::per_t::<i32>(Hour)
1213 + minute_diff.widen::<i32>() * Second::per_t::<i32>(Minute)
1214 + second_diff.widen::<i32>();
1215
1216 let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
1217 (
1218 seconds - 1,
1219 nanosecond_diff + Nanosecond::per_t::<i32>(Second),
1220 )
1221 } else if seconds < 0 && nanosecond_diff > 0 {
1222 (
1223 seconds + 1,
1224 nanosecond_diff - Nanosecond::per_t::<i32>(Second),
1225 )
1226 } else {
1227 (seconds, nanosecond_diff)
1228 };
1229
1230 unsafe { Duration::new_unchecked(seconds.widen(), nanoseconds) }
1232 }
1233}