1#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::cmp::Ordering;
6use core::hash::{Hash, Hasher};
7use core::ops::{Add, AddAssign, Sub, SubAssign};
8use core::time::Duration as StdDuration;
9use core::{fmt, hint};
10#[cfg(feature = "formatting")]
11use std::io;
12
13use deranged::{RangedU8, RangedU32};
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};
22#[cfg(feature = "parsing")]
23use crate::parsing::Parsable;
24use crate::util::DateAdjustment;
25use crate::{Duration, error};
26
27#[repr(u8)]
30#[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_receiver_is_total_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)]
31pub(crate) enum Padding {
32 #[allow(clippy::missing_docs_in_private_items)]
33 Optimize,
34}
35
36type Hours = RangedU8<0, { Hour::per_t::<u8>(Day) - 1 }>;
38type Minutes = RangedU8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
40type Seconds = RangedU8<0, { Second::per_t::<u8>(Minute) - 1 }>;
42type Nanoseconds = RangedU32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>;
44
45#[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_receiver_is_total_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)]
52#[cfg_attr(not(docsrs), repr(C))]
53pub struct Time {
54 #[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 #[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>(&self, state: &mut H)
84 where
85 H: Hasher,
86 {
87 self.as_u64().hash(state)
88 }
89}
90
91impl PartialEq for Time {
92 #[inline]
93 fn eq(&self, other: &Self) -> bool {
94 self.as_u64().eq(&other.as_u64())
95 }
96}
97
98impl PartialOrd for Time {
99 #[inline]
100 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
101 Some(self.cmp(other))
102 }
103}
104
105impl Ord for Time {
106 #[inline]
107 fn cmp(&self, other: &Self) -> Ordering {
108 self.as_u64().cmp(&other.as_u64())
109 }
110}
111
112impl Time {
113 #[inline]
116 pub(crate) const fn as_u64(self) -> u64 {
117 unsafe { core::mem::transmute(self) }
121 }
122
123 #[doc(alias = "MIN")]
131 pub const MIDNIGHT: Self =
132 Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
133
134 pub const MAX: Self =
143 Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
144
145 #[doc(hidden)]
154 #[inline]
155 #[track_caller]
156 pub const unsafe fn __from_hms_nanos_unchecked(
157 hour: u8,
158 minute: u8,
159 second: u8,
160 nanosecond: u32,
161 ) -> Self {
162 unsafe {
164 Self::from_hms_nanos_ranged(
165 Hours::new_unchecked(hour),
166 Minutes::new_unchecked(minute),
167 Seconds::new_unchecked(second),
168 Nanoseconds::new_unchecked(nanosecond),
169 )
170 }
171 }
172
173 #[inline]
187 pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
188 Ok(Self::from_hms_nanos_ranged(
189 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
190 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
191 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
192 Nanoseconds::MIN,
193 ))
194 }
195
196 #[inline]
198 pub(crate) const fn from_hms_nanos_ranged(
199 hour: Hours,
200 minute: Minutes,
201 second: Seconds,
202 nanosecond: Nanoseconds,
203 ) -> Self {
204 Self {
205 hour,
206 minute,
207 second,
208 nanosecond,
209 padding: Padding::Optimize,
210 }
211 }
212
213 #[inline]
228 pub const fn from_hms_milli(
229 hour: u8,
230 minute: u8,
231 second: u8,
232 millisecond: u16,
233 ) -> Result<Self, error::ComponentRange> {
234 Ok(Self::from_hms_nanos_ranged(
235 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
236 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
237 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
238 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)),
239 ))
240 }
241
242 #[inline]
257 pub const fn from_hms_micro(
258 hour: u8,
259 minute: u8,
260 second: u8,
261 microsecond: u32,
262 ) -> Result<Self, error::ComponentRange> {
263 Ok(Self::from_hms_nanos_ranged(
264 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
265 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
266 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
267 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)),
268 ))
269 }
270
271 #[inline]
286 pub const fn from_hms_nano(
287 hour: u8,
288 minute: u8,
289 second: u8,
290 nanosecond: u32,
291 ) -> Result<Self, error::ComponentRange> {
292 Ok(Self::from_hms_nanos_ranged(
293 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("hour"));
}
}ensure_ranged!(Hours: hour),
294 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("minute"));
}
}ensure_ranged!(Minutes: minute),
295 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("second"));
}
}ensure_ranged!(Seconds: second),
296 match <Nanoseconds>::new(nanosecond) {
Some(val) => val,
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange::unconditional("nanosecond"));
}
}ensure_ranged!(Nanoseconds: nanosecond),
297 ))
298 }
299
300 #[inline]
308 pub const fn as_hms(self) -> (u8, u8, u8) {
309 (self.hour.get(), self.minute.get(), self.second.get())
310 }
311
312 #[inline]
320 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
321 (
322 self.hour.get(),
323 self.minute.get(),
324 self.second.get(),
325 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16,
326 )
327 }
328
329 #[inline]
340 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
341 (
342 self.hour.get(),
343 self.minute.get(),
344 self.second.get(),
345 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
346 )
347 }
348
349 #[inline]
360 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
361 (
362 self.hour.get(),
363 self.minute.get(),
364 self.second.get(),
365 self.nanosecond.get(),
366 )
367 }
368
369 #[cfg(feature = "quickcheck")]
371 #[inline]
372 pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
373 (self.hour, self.minute, self.second, self.nanosecond)
374 }
375
376 #[inline]
386 pub const fn hour(self) -> u8 {
387 self.hour.get()
388 }
389
390 #[inline]
400 pub const fn minute(self) -> u8 {
401 self.minute.get()
402 }
403
404 #[inline]
414 pub const fn second(self) -> u8 {
415 self.second.get()
416 }
417
418 #[inline]
428 pub const fn millisecond(self) -> u16 {
429 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
430 }
431
432 #[inline]
442 pub const fn microsecond(self) -> u32 {
443 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
444 }
445
446 #[inline]
456 pub const fn nanosecond(self) -> u32 {
457 self.nanosecond.get()
458 }
459
460 #[inline]
470 pub const fn duration_until(self, other: Self) -> Duration {
471 let mut nanoseconds =
472 other.nanosecond.get().cast_signed() - self.nanosecond.get().cast_signed();
473 let seconds = other.second.get().cast_signed() - self.second.get().cast_signed();
474 let minutes = other.minute.get().cast_signed() - self.minute.get().cast_signed();
475 let hours = other.hour.get().cast_signed() - self.hour.get().cast_signed();
476
477 unsafe {
480 hint::assert_unchecked(
481 nanoseconds
482 >= Nanoseconds::MIN.get().cast_signed() - Nanoseconds::MAX.get().cast_signed(),
483 );
484 hint::assert_unchecked(
485 nanoseconds
486 <= Nanoseconds::MAX.get().cast_signed() - Nanoseconds::MIN.get().cast_signed(),
487 );
488 hint::assert_unchecked(
489 seconds >= Seconds::MIN.get().cast_signed() - Seconds::MAX.get().cast_signed(),
490 );
491 hint::assert_unchecked(
492 seconds <= Seconds::MAX.get().cast_signed() - Seconds::MIN.get().cast_signed(),
493 );
494 hint::assert_unchecked(
495 minutes >= Minutes::MIN.get().cast_signed() - Minutes::MAX.get().cast_signed(),
496 );
497 hint::assert_unchecked(
498 minutes <= Minutes::MAX.get().cast_signed() - Minutes::MIN.get().cast_signed(),
499 );
500 hint::assert_unchecked(
501 hours >= Hours::MIN.get().cast_signed() - Hours::MAX.get().cast_signed(),
502 );
503 hint::assert_unchecked(
504 hours <= Hours::MAX.get().cast_signed() - Hours::MIN.get().cast_signed(),
505 );
506 }
507
508 let mut total_seconds = hours as i32 * Second::per_t::<i32>(Hour)
509 + minutes as i32 * Second::per_t::<i32>(Minute)
510 + seconds as i32;
511
512 #[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);
513
514 if total_seconds < 0 {
515 total_seconds += Second::per_t::<i32>(Day);
516 }
517
518 unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) }
520 }
521
522 #[inline]
532 pub const fn duration_since(self, other: Self) -> Duration {
533 other.duration_until(self)
534 }
535
536 #[inline]
539 pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
540 let mut nanoseconds = self.nanosecond.get().cast_signed() + duration.subsec_nanoseconds();
541 let mut seconds = self.second.get().cast_signed()
542 + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
543 let mut minutes = self.minute.get().cast_signed()
544 + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
545 let mut hours = self.hour.get().cast_signed()
546 + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
547 let mut date_adjustment = DateAdjustment::None;
548
549 #[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);
550 #[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);
551 #[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);
552 if hours >= Hour::per_t(Day) {
553 hours -= Hour::per_t::<i8>(Day);
554 date_adjustment = DateAdjustment::Next;
555 } else if hours < 0 {
556 hours += Hour::per_t::<i8>(Day);
557 date_adjustment = DateAdjustment::Previous;
558 }
559
560 (
561 date_adjustment,
562 unsafe {
564 Self::__from_hms_nanos_unchecked(
565 hours.cast_unsigned(),
566 minutes.cast_unsigned(),
567 seconds.cast_unsigned(),
568 nanoseconds.cast_unsigned(),
569 )
570 },
571 )
572 }
573
574 #[inline]
577 pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
578 let mut nanoseconds = self.nanosecond.get().cast_signed() - duration.subsec_nanoseconds();
579 let mut seconds = self.second.get().cast_signed()
580 - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
581 let mut minutes = self.minute.get().cast_signed()
582 - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
583 let mut hours = self.hour.get().cast_signed()
584 - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
585 let mut date_adjustment = DateAdjustment::None;
586
587 #[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);
588 #[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);
589 #[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);
590 if hours >= Hour::per_t(Day) {
591 hours -= Hour::per_t::<i8>(Day);
592 date_adjustment = DateAdjustment::Next;
593 } else if hours < 0 {
594 hours += Hour::per_t::<i8>(Day);
595 date_adjustment = DateAdjustment::Previous;
596 }
597
598 (
599 date_adjustment,
600 unsafe {
602 Self::__from_hms_nanos_unchecked(
603 hours.cast_unsigned(),
604 minutes.cast_unsigned(),
605 seconds.cast_unsigned(),
606 nanoseconds.cast_unsigned(),
607 )
608 },
609 )
610 }
611
612 #[inline]
615 pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
616 let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
617 let mut second =
618 self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
619 let mut minute = self.minute.get()
620 + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
621 as u8;
622 let mut hour = self.hour.get()
623 + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
624 let mut is_next_day = false;
625
626 #[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);
627 #[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);
628 #[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);
629 if hour >= Hour::per_t::<u8>(Day) {
630 hour -= Hour::per_t::<u8>(Day);
631 is_next_day = true;
632 }
633
634 (
635 is_next_day,
636 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
638 )
639 }
640
641 #[inline]
644 pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
645 let mut nanosecond =
646 self.nanosecond.get().cast_signed() - duration.subsec_nanos().cast_signed();
647 let mut second = self.second.get().cast_signed()
648 - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
649 let mut minute = self.minute.get().cast_signed()
650 - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
651 as i8;
652 let mut hour = self.hour.get().cast_signed()
653 - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
654 let mut is_previous_day = false;
655
656 #[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);
657 #[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);
658 #[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);
659 if hour < 0 {
660 hour += Hour::per_t::<i8>(Day);
661 is_previous_day = true;
662 }
663
664 (
665 is_previous_day,
666 unsafe {
668 Self::__from_hms_nanos_unchecked(
669 hour.cast_unsigned(),
670 minute.cast_unsigned(),
671 second.cast_unsigned(),
672 nanosecond.cast_unsigned(),
673 )
674 },
675 )
676 }
677
678 #[must_use = "This method does not mutate the original `Time`."]
689 #[inline]
690 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
691 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);
692 Ok(self)
693 }
694
695 #[must_use = "This method does not mutate the original `Time`."]
702 #[inline]
703 pub const fn truncate_to_hour(mut self) -> Self {
704 self.minute = Minutes::MIN;
705 self.second = Seconds::MIN;
706 self.nanosecond = Nanoseconds::MIN;
707 self
708 }
709
710 #[must_use = "This method does not mutate the original `Time`."]
721 #[inline]
722 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
723 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);
724 Ok(self)
725 }
726
727 #[must_use = "This method does not mutate the original `Time`."]
737 #[inline]
738 pub const fn truncate_to_minute(mut self) -> Self {
739 self.second = Seconds::MIN;
740 self.nanosecond = Nanoseconds::MIN;
741 self
742 }
743
744 #[must_use = "This method does not mutate the original `Time`."]
755 #[inline]
756 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
757 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);
758 Ok(self)
759 }
760
761 #[must_use = "This method does not mutate the original `Time`."]
771 #[inline]
772 pub const fn truncate_to_second(mut self) -> Self {
773 self.nanosecond = Nanoseconds::MIN;
774 self
775 }
776
777 #[must_use = "This method does not mutate the original `Time`."]
792 #[inline]
793 pub const fn replace_millisecond(
794 mut self,
795 millisecond: u16,
796 ) -> Result<Self, error::ComponentRange> {
797 self.nanosecond =
798 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));
799 Ok(self)
800 }
801
802 #[must_use = "This method does not mutate the original `Time`."]
813 #[inline]
814 pub const fn truncate_to_millisecond(mut self) -> Self {
815 self.nanosecond = unsafe {
817 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000_000))
818 };
819 self
820 }
821
822 #[must_use = "This method does not mutate the original `Time`."]
837 #[inline]
838 pub const fn replace_microsecond(
839 mut self,
840 microsecond: u32,
841 ) -> Result<Self, error::ComponentRange> {
842 self.nanosecond =
843 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));
844 Ok(self)
845 }
846
847 #[must_use = "This method does not mutate the original `Time`."]
857 #[inline]
858 pub const fn truncate_to_microsecond(mut self) -> Self {
859 self.nanosecond = unsafe {
861 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000))
862 };
863 self
864 }
865
866 #[must_use = "This method does not mutate the original `Time`."]
881 #[inline]
882 pub const fn replace_nanosecond(
883 mut self,
884 nanosecond: u32,
885 ) -> Result<Self, error::ComponentRange> {
886 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);
887 Ok(self)
888 }
889}
890
891#[cfg(feature = "formatting")]
892impl Time {
893 #[inline]
895 pub fn format_into(
896 self,
897 output: &mut (impl io::Write + ?Sized),
898 format: &(impl Formattable + ?Sized),
899 ) -> Result<usize, error::Format> {
900 format.format_into(output, None, Some(self), None)
901 }
902
903 #[inline]
913 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
914 format.format(None, Some(self), None)
915 }
916}
917
918#[cfg(feature = "parsing")]
919impl Time {
920 #[inline]
931 pub fn parse(
932 input: &str,
933 description: &(impl Parsable + ?Sized),
934 ) -> Result<Self, error::Parse> {
935 description.parse_time(input.as_bytes())
936 }
937}
938
939mod private {
940 #[non_exhaustive]
942 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for TimeMetadata {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "TimeMetadata",
"subsecond_width", &self.subsecond_width, "subsecond_value",
&&self.subsecond_value)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for TimeMetadata {
#[inline]
fn clone(&self) -> TimeMetadata {
let _: ::core::clone::AssertParamIsClone<u8>;
let _: ::core::clone::AssertParamIsClone<u32>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for TimeMetadata { }Copy)]
943 pub struct TimeMetadata {
944 pub(super) subsecond_width: u8,
946 pub(super) subsecond_value: u32,
949 }
950}
951use private::TimeMetadata;
952
953impl SmartDisplay for Time {
954 type Metadata = TimeMetadata;
955
956 #[inline]
957 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
958 let (subsecond_value, subsecond_width) = match self.nanosecond() {
959 nanos if nanos % 10 != 0 => (nanos, 9),
960 nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
961 nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
962 nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
963 nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
964 nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
965 nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
966 nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
967 nanos => (nanos / 100_000_000, 1),
968 };
969
970 let formatted_width = 0 +
::powerfmt::smart_display::Metadata::padded_width_of(&self.hour.get(),
::powerfmt::smart_display::FormatterOptions::default()) +
::powerfmt::smart_display::Metadata::padded_width_of(&":",
::powerfmt::smart_display::FormatterOptions::default()) +
::powerfmt::smart_display::Metadata::padded_width_of(&self.minute.get(),
*::powerfmt::smart_display::FormatterOptions::default().with_width(Some(2)).with_fill('0'))
+
::powerfmt::smart_display::Metadata::padded_width_of(&":",
::powerfmt::smart_display::FormatterOptions::default()) +
::powerfmt::smart_display::Metadata::padded_width_of(&self.second.get(),
*::powerfmt::smart_display::FormatterOptions::default().with_width(Some(2)).with_fill('0'))
+
::powerfmt::smart_display::Metadata::padded_width_of(&".",
::powerfmt::smart_display::FormatterOptions::default())smart_display::padded_width_of!(
971 self.hour.get(),
972 ":",
973 self.minute.get() => width(2) fill('0'),
974 ":",
975 self.second.get() => width(2) fill('0'),
976 ".",
977 ) + subsecond_width;
978
979 Metadata::new(
980 formatted_width,
981 self,
982 TimeMetadata {
983 subsecond_width: subsecond_width.truncate(),
984 subsecond_value,
985 },
986 )
987 }
988
989 #[inline]
990 fn fmt_with_metadata(
991 &self,
992 f: &mut fmt::Formatter<'_>,
993 metadata: Metadata<Self>,
994 ) -> fmt::Result {
995 let subsecond_width = metadata.subsecond_width.extend();
996 let subsecond_value = metadata.subsecond_value;
997
998 f.pad_with_width(
999 metadata.unpadded_width(),
1000 format_args!("{0}:{1:02}:{2:02}.{3:04$}", self.hour, self.minute, self.second,
subsecond_value, subsecond_width)format_args!(
1001 "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
1002 self.hour, self.minute, self.second
1003 ),
1004 )
1005 }
1006}
1007
1008impl fmt::Display for Time {
1009 #[inline]
1010 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1011 SmartDisplay::fmt(self, f)
1012 }
1013}
1014
1015impl fmt::Debug for Time {
1016 #[inline]
1017 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1018 fmt::Display::fmt(self, f)
1019 }
1020}
1021
1022impl Add<Duration> for Time {
1023 type Output = Self;
1024
1025 #[inline]
1034 fn add(self, duration: Duration) -> Self::Output {
1035 self.adjusting_add(duration).1
1036 }
1037}
1038
1039impl AddAssign<Duration> for Time {
1040 #[inline]
1041 fn add_assign(&mut self, rhs: Duration) {
1042 *self = *self + rhs;
1043 }
1044}
1045
1046impl Add<StdDuration> for Time {
1047 type Output = Self;
1048
1049 #[inline]
1058 fn add(self, duration: StdDuration) -> Self::Output {
1059 self.adjusting_add_std(duration).1
1060 }
1061}
1062
1063impl AddAssign<StdDuration> for Time {
1064 #[inline]
1065 fn add_assign(&mut self, rhs: StdDuration) {
1066 *self = *self + rhs;
1067 }
1068}
1069
1070impl Sub<Duration> for Time {
1071 type Output = Self;
1072
1073 #[inline]
1082 fn sub(self, duration: Duration) -> Self::Output {
1083 self.adjusting_sub(duration).1
1084 }
1085}
1086
1087impl SubAssign<Duration> for Time {
1088 #[inline]
1089 fn sub_assign(&mut self, rhs: Duration) {
1090 *self = *self - rhs;
1091 }
1092}
1093
1094impl Sub<StdDuration> for Time {
1095 type Output = Self;
1096
1097 #[inline]
1106 fn sub(self, duration: StdDuration) -> Self::Output {
1107 self.adjusting_sub_std(duration).1
1108 }
1109}
1110
1111impl SubAssign<StdDuration> for Time {
1112 #[inline]
1113 fn sub_assign(&mut self, rhs: StdDuration) {
1114 *self = *self - rhs;
1115 }
1116}
1117
1118impl Sub for Time {
1119 type Output = Duration;
1120
1121 #[inline]
1133 fn sub(self, rhs: Self) -> Self::Output {
1134 let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
1135 let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
1136 let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
1137 let nanosecond_diff =
1138 self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
1139
1140 let seconds = hour_diff.extend::<i32>() * Second::per_t::<i32>(Hour)
1141 + minute_diff.extend::<i32>() * Second::per_t::<i32>(Minute)
1142 + second_diff.extend::<i32>();
1143
1144 let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
1145 (
1146 seconds - 1,
1147 nanosecond_diff + Nanosecond::per_t::<i32>(Second),
1148 )
1149 } else if seconds < 0 && nanosecond_diff > 0 {
1150 (
1151 seconds + 1,
1152 nanosecond_diff - Nanosecond::per_t::<i32>(Second),
1153 )
1154 } else {
1155 (seconds, nanosecond_diff)
1156 };
1157
1158 unsafe { Duration::new_unchecked(seconds.extend(), nanoseconds) }
1160 }
1161}