1#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::cmp::Ordering;
6use core::hash::{Hash, Hasher};
7use core::ops::{Add, Sub};
8use core::time::Duration as StdDuration;
9use core::{fmt, hint};
10#[cfg(feature = "formatting")]
11use std::io;
12
13use deranged::{RangedU32, RangedU8};
14use num_conv::prelude::*;
15use powerfmt::ext::FormatterExt;
16use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
17
18use crate::convert::*;
19#[cfg(feature = "formatting")]
20use crate::formatting::Formattable;
21use crate::internal_macros::{cascade, ensure_ranged, impl_add_assign, impl_sub_assign};
22#[cfg(feature = "parsing")]
23use crate::parsing::Parsable;
24use crate::util::DateAdjustment;
25use crate::{error, Duration};
26
27#[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)]
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: Hasher>(&self, state: &mut H) {
84 self.as_u64().hash(state)
85 }
86}
87
88impl PartialEq for Time {
89 #[inline]
90 fn eq(&self, other: &Self) -> bool {
91 self.as_u64().eq(&other.as_u64())
92 }
93}
94
95impl PartialOrd for Time {
96 #[inline]
97 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
98 Some(self.cmp(other))
99 }
100}
101
102impl Ord for Time {
103 #[inline]
104 fn cmp(&self, other: &Self) -> Ordering {
105 self.as_u64().cmp(&other.as_u64())
106 }
107}
108
109impl Time {
110 #[inline]
113 pub(crate) const fn as_u64(self) -> u64 {
114 unsafe { core::mem::transmute(self) }
118 }
119
120 #[doc(alias = "MIN")]
128 pub const MIDNIGHT: Self =
129 Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
130
131 pub const MAX: Self =
140 Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
141
142 #[doc(hidden)]
151 #[inline]
152 #[track_caller]
153 pub const unsafe fn __from_hms_nanos_unchecked(
154 hour: u8,
155 minute: u8,
156 second: u8,
157 nanosecond: u32,
158 ) -> Self {
159 unsafe {
161 Self::from_hms_nanos_ranged(
162 Hours::new_unchecked(hour),
163 Minutes::new_unchecked(minute),
164 Seconds::new_unchecked(second),
165 Nanoseconds::new_unchecked(nanosecond),
166 )
167 }
168 }
169
170 #[inline]
184 pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
185 Ok(Self::from_hms_nanos_ranged(
186 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "hour",
minimum: <Hours>::MIN.get() as i64,
maximum: <Hours>::MAX.get() as i64,
value: hour as i64,
conditional_message: None,
});
}
}ensure_ranged!(Hours: hour),
187 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "minute",
minimum: <Minutes>::MIN.get() as i64,
maximum: <Minutes>::MAX.get() as i64,
value: minute as i64,
conditional_message: None,
});
}
}ensure_ranged!(Minutes: minute),
188 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "second",
minimum: <Seconds>::MIN.get() as i64,
maximum: <Seconds>::MAX.get() as i64,
value: second as i64,
conditional_message: None,
});
}
}ensure_ranged!(Seconds: second),
189 Nanoseconds::MIN,
190 ))
191 }
192
193 #[inline]
195 pub(crate) const fn from_hms_nanos_ranged(
196 hour: Hours,
197 minute: Minutes,
198 second: Seconds,
199 nanosecond: Nanoseconds,
200 ) -> Self {
201 Self {
202 hour,
203 minute,
204 second,
205 nanosecond,
206 padding: Padding::Optimize,
207 }
208 }
209
210 #[inline]
225 pub const fn from_hms_milli(
226 hour: u8,
227 minute: u8,
228 second: u8,
229 millisecond: u16,
230 ) -> Result<Self, error::ComponentRange> {
231 Ok(Self::from_hms_nanos_ranged(
232 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "hour",
minimum: <Hours>::MIN.get() as i64,
maximum: <Hours>::MAX.get() as i64,
value: hour as i64,
conditional_message: None,
});
}
}ensure_ranged!(Hours: hour),
233 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "minute",
minimum: <Minutes>::MIN.get() as i64,
maximum: <Minutes>::MAX.get() as i64,
value: minute as i64,
conditional_message: None,
});
}
}ensure_ranged!(Minutes: minute),
234 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "second",
minimum: <Seconds>::MIN.get() as i64,
maximum: <Seconds>::MAX.get() as i64,
value: second as i64,
conditional_message: None,
});
}
}ensure_ranged!(Seconds: second),
235 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();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "millisecond",
minimum: <Nanoseconds>::MIN.get() as i64 /
Nanosecond::per_t::<u32>(Millisecond) as i64,
maximum: <Nanoseconds>::MAX.get() as i64 /
Nanosecond::per_t::<u32>(Millisecond) as i64,
value: millisecond as i64,
conditional_message: None,
});
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange {
name: "millisecond",
minimum: <Nanoseconds>::MIN.get() as i64 /
Nanosecond::per_t::<u32>(Millisecond) as i64,
maximum: <Nanoseconds>::MAX.get() as i64 /
Nanosecond::per_t::<u32>(Millisecond) as i64,
value: millisecond as i64,
conditional_message: None,
});
}
}ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)),
236 ))
237 }
238
239 #[inline]
254 pub const fn from_hms_micro(
255 hour: u8,
256 minute: u8,
257 second: u8,
258 microsecond: u32,
259 ) -> Result<Self, error::ComponentRange> {
260 Ok(Self::from_hms_nanos_ranged(
261 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "hour",
minimum: <Hours>::MIN.get() as i64,
maximum: <Hours>::MAX.get() as i64,
value: hour as i64,
conditional_message: None,
});
}
}ensure_ranged!(Hours: hour),
262 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "minute",
minimum: <Minutes>::MIN.get() as i64,
maximum: <Minutes>::MAX.get() as i64,
value: minute as i64,
conditional_message: None,
});
}
}ensure_ranged!(Minutes: minute),
263 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "second",
minimum: <Seconds>::MIN.get() as i64,
maximum: <Seconds>::MAX.get() as i64,
value: second as i64,
conditional_message: None,
});
}
}ensure_ranged!(Seconds: second),
264 match (microsecond).checked_mul(Nanosecond::per_t::<u32>(Microsecond)) {
Some(val) =>
match <Nanoseconds>::new(val) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "microsecond",
minimum: <Nanoseconds>::MIN.get() as i64 /
Nanosecond::per_t::<u32>(Microsecond) as i64,
maximum: <Nanoseconds>::MAX.get() as i64 /
Nanosecond::per_t::<u32>(Microsecond) as i64,
value: microsecond as i64,
conditional_message: None,
});
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange {
name: "microsecond",
minimum: <Nanoseconds>::MIN.get() as i64 /
Nanosecond::per_t::<u32>(Microsecond) as i64,
maximum: <Nanoseconds>::MAX.get() as i64 /
Nanosecond::per_t::<u32>(Microsecond) as i64,
value: microsecond as i64,
conditional_message: None,
});
}
}ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)),
265 ))
266 }
267
268 #[inline]
283 pub const fn from_hms_nano(
284 hour: u8,
285 minute: u8,
286 second: u8,
287 nanosecond: u32,
288 ) -> Result<Self, error::ComponentRange> {
289 Ok(Self::from_hms_nanos_ranged(
290 match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "hour",
minimum: <Hours>::MIN.get() as i64,
maximum: <Hours>::MAX.get() as i64,
value: hour as i64,
conditional_message: None,
});
}
}ensure_ranged!(Hours: hour),
291 match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "minute",
minimum: <Minutes>::MIN.get() as i64,
maximum: <Minutes>::MAX.get() as i64,
value: minute as i64,
conditional_message: None,
});
}
}ensure_ranged!(Minutes: minute),
292 match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "second",
minimum: <Seconds>::MIN.get() as i64,
maximum: <Seconds>::MAX.get() as i64,
value: second as i64,
conditional_message: None,
});
}
}ensure_ranged!(Seconds: second),
293 match <Nanoseconds>::new(nanosecond) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "nanosecond",
minimum: <Nanoseconds>::MIN.get() as i64,
maximum: <Nanoseconds>::MAX.get() as i64,
value: nanosecond as i64,
conditional_message: None,
});
}
}ensure_ranged!(Nanoseconds: nanosecond),
294 ))
295 }
296
297 #[inline]
305 pub const fn as_hms(self) -> (u8, u8, u8) {
306 (self.hour.get(), self.minute.get(), self.second.get())
307 }
308
309 #[inline]
317 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
318 (
319 self.hour.get(),
320 self.minute.get(),
321 self.second.get(),
322 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16,
323 )
324 }
325
326 #[inline]
337 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
338 (
339 self.hour.get(),
340 self.minute.get(),
341 self.second.get(),
342 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
343 )
344 }
345
346 #[inline]
357 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
358 (
359 self.hour.get(),
360 self.minute.get(),
361 self.second.get(),
362 self.nanosecond.get(),
363 )
364 }
365
366 #[cfg(feature = "quickcheck")]
368 #[inline]
369 pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
370 (self.hour, self.minute, self.second, self.nanosecond)
371 }
372
373 #[inline]
383 pub const fn hour(self) -> u8 {
384 self.hour.get()
385 }
386
387 #[inline]
397 pub const fn minute(self) -> u8 {
398 self.minute.get()
399 }
400
401 #[inline]
411 pub const fn second(self) -> u8 {
412 self.second.get()
413 }
414
415 #[inline]
425 pub const fn millisecond(self) -> u16 {
426 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
427 }
428
429 #[inline]
439 pub const fn microsecond(self) -> u32 {
440 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
441 }
442
443 #[inline]
453 pub const fn nanosecond(self) -> u32 {
454 self.nanosecond.get()
455 }
456
457 #[inline]
467 pub const fn duration_until(self, other: Self) -> Duration {
468 let mut nanoseconds = other.nanosecond.get() as i32 - self.nanosecond.get() as i32;
469 let seconds = other.second.get() as i8 - self.second.get() as i8;
470 let minutes = other.minute.get() as i8 - self.minute.get() as i8;
471 let hours = other.hour.get() as i8 - self.hour.get() as i8;
472
473 unsafe {
476 hint::assert_unchecked(
477 nanoseconds >= Nanoseconds::MIN.get() as i32 - Nanoseconds::MAX.get() as i32,
478 );
479 hint::assert_unchecked(
480 nanoseconds <= Nanoseconds::MAX.get() as i32 - Nanoseconds::MIN.get() as i32,
481 );
482 hint::assert_unchecked(seconds >= Seconds::MIN.get() as i8 - Seconds::MAX.get() as i8);
483 hint::assert_unchecked(seconds <= Seconds::MAX.get() as i8 - Seconds::MIN.get() as i8);
484 hint::assert_unchecked(minutes >= Minutes::MIN.get() as i8 - Minutes::MAX.get() as i8);
485 hint::assert_unchecked(minutes <= Minutes::MAX.get() as i8 - Minutes::MIN.get() as i8);
486 hint::assert_unchecked(hours >= Hours::MIN.get() as i8 - Hours::MAX.get() as i8);
487 hint::assert_unchecked(hours <= Hours::MAX.get() as i8 - Hours::MIN.get() as i8);
488 }
489
490 let mut total_seconds = hours as i32 * Second::per_t::<i32>(Hour)
491 + minutes as i32 * Second::per_t::<i32>(Minute)
492 + seconds as i32;
493
494 #[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);
495
496 if total_seconds < 0 {
497 total_seconds += Second::per_t::<i32>(Day);
498 }
499
500 unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) }
502 }
503
504 #[inline]
514 pub const fn duration_since(self, other: Self) -> Duration {
515 other.duration_until(self)
516 }
517
518 #[inline]
521 pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
522 let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds();
523 let mut seconds = self.second.get() as i8
524 + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
525 let mut minutes =
526 self.minute.get() as i8 + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
527 let mut hours =
528 self.hour.get() as i8 + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
529 let mut date_adjustment = DateAdjustment::None;
530
531 #[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);
532 #[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);
533 #[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);
534 if hours >= Hour::per_t(Day) {
535 hours -= Hour::per_t::<i8>(Day);
536 date_adjustment = DateAdjustment::Next;
537 } else if hours < 0 {
538 hours += Hour::per_t::<i8>(Day);
539 date_adjustment = DateAdjustment::Previous;
540 }
541
542 (
543 date_adjustment,
544 unsafe {
546 Self::__from_hms_nanos_unchecked(
547 hours as u8,
548 minutes as u8,
549 seconds as u8,
550 nanoseconds as u32,
551 )
552 },
553 )
554 }
555
556 #[inline]
559 pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
560 let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
561 let mut seconds = self.second.get() as i8
562 - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
563 let mut minutes =
564 self.minute.get() as i8 - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
565 let mut hours =
566 self.hour.get() as i8 - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
567 let mut date_adjustment = DateAdjustment::None;
568
569 #[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);
570 #[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);
571 #[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);
572 if hours >= Hour::per_t(Day) {
573 hours -= Hour::per_t::<i8>(Day);
574 date_adjustment = DateAdjustment::Next;
575 } else if hours < 0 {
576 hours += Hour::per_t::<i8>(Day);
577 date_adjustment = DateAdjustment::Previous;
578 }
579
580 (
581 date_adjustment,
582 unsafe {
584 Self::__from_hms_nanos_unchecked(
585 hours as u8,
586 minutes as u8,
587 seconds as u8,
588 nanoseconds as u32,
589 )
590 },
591 )
592 }
593
594 #[inline]
597 pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
598 let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
599 let mut second =
600 self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
601 let mut minute = self.minute.get()
602 + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
603 as u8;
604 let mut hour = self.hour.get()
605 + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
606 let mut is_next_day = false;
607
608 #[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);
609 #[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);
610 #[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);
611 if hour >= Hour::per_t::<u8>(Day) {
612 hour -= Hour::per_t::<u8>(Day);
613 is_next_day = true;
614 }
615
616 (
617 is_next_day,
618 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
620 )
621 }
622
623 #[inline]
626 pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
627 let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
628 let mut second =
629 self.second.get() as i8 - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
630 let mut minute = self.minute.get() as i8
631 - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
632 as i8;
633 let mut hour = self.hour.get() as i8
634 - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
635 let mut is_previous_day = false;
636
637 #[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);
638 #[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);
639 #[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);
640 if hour < 0 {
641 hour += Hour::per_t::<i8>(Day);
642 is_previous_day = true;
643 }
644
645 (
646 is_previous_day,
647 unsafe {
649 Self::__from_hms_nanos_unchecked(
650 hour as u8,
651 minute as u8,
652 second as u8,
653 nanosecond as u32,
654 )
655 },
656 )
657 }
658
659 #[must_use = "This method does not mutate the original `Time`."]
670 #[inline]
671 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
672 self.hour = match <Hours>::new(hour) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "hour",
minimum: <Hours>::MIN.get() as i64,
maximum: <Hours>::MAX.get() as i64,
value: hour as i64,
conditional_message: None,
});
}
}ensure_ranged!(Hours: hour);
673 Ok(self)
674 }
675
676 #[must_use = "This method does not mutate the original `Time`."]
687 #[inline]
688 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
689 self.minute = match <Minutes>::new(minute) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "minute",
minimum: <Minutes>::MIN.get() as i64,
maximum: <Minutes>::MAX.get() as i64,
value: minute as i64,
conditional_message: None,
});
}
}ensure_ranged!(Minutes: minute);
690 Ok(self)
691 }
692
693 #[must_use = "This method does not mutate the original `Time`."]
704 #[inline]
705 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
706 self.second = match <Seconds>::new(second) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "second",
minimum: <Seconds>::MIN.get() as i64,
maximum: <Seconds>::MAX.get() as i64,
value: second as i64,
conditional_message: None,
});
}
}ensure_ranged!(Seconds: second);
707 Ok(self)
708 }
709
710 #[must_use = "This method does not mutate the original `Time`."]
723 #[inline]
724 pub const fn replace_millisecond(
725 mut self,
726 millisecond: u16,
727 ) -> Result<Self, error::ComponentRange> {
728 self.nanosecond =
729 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();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "millisecond",
minimum: <Nanoseconds>::MIN.get() as i64 /
Nanosecond::per_t::<u32>(Millisecond) as i64,
maximum: <Nanoseconds>::MAX.get() as i64 /
Nanosecond::per_t::<u32>(Millisecond) as i64,
value: millisecond as i64,
conditional_message: None,
});
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange {
name: "millisecond",
minimum: <Nanoseconds>::MIN.get() as i64 /
Nanosecond::per_t::<u32>(Millisecond) as i64,
maximum: <Nanoseconds>::MAX.get() as i64 /
Nanosecond::per_t::<u32>(Millisecond) as i64,
value: millisecond as i64,
conditional_message: None,
});
}
}ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
730 Ok(self)
731 }
732
733 #[must_use = "This method does not mutate the original `Time`."]
746 #[inline]
747 pub const fn replace_microsecond(
748 mut self,
749 microsecond: u32,
750 ) -> Result<Self, error::ComponentRange> {
751 self.nanosecond =
752 match (microsecond).checked_mul(Nanosecond::per_t::<u32>(Microsecond)) {
Some(val) =>
match <Nanoseconds>::new(val) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "microsecond",
minimum: <Nanoseconds>::MIN.get() as i64 /
Nanosecond::per_t::<u32>(Microsecond) as i64,
maximum: <Nanoseconds>::MAX.get() as i64 /
Nanosecond::per_t::<u32>(Microsecond) as i64,
value: microsecond as i64,
conditional_message: None,
});
}
},
None => {
crate::hint::cold_path();
return Err(crate::error::ComponentRange {
name: "microsecond",
minimum: <Nanoseconds>::MIN.get() as i64 /
Nanosecond::per_t::<u32>(Microsecond) as i64,
maximum: <Nanoseconds>::MAX.get() as i64 /
Nanosecond::per_t::<u32>(Microsecond) as i64,
value: microsecond as i64,
conditional_message: None,
});
}
}ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
753 Ok(self)
754 }
755
756 #[must_use = "This method does not mutate the original `Time`."]
769 #[inline]
770 pub const fn replace_nanosecond(
771 mut self,
772 nanosecond: u32,
773 ) -> Result<Self, error::ComponentRange> {
774 self.nanosecond = match <Nanoseconds>::new(nanosecond) {
Some(val) => val,
None => {
crate::hint::cold_path();
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: "nanosecond",
minimum: <Nanoseconds>::MIN.get() as i64,
maximum: <Nanoseconds>::MAX.get() as i64,
value: nanosecond as i64,
conditional_message: None,
});
}
}ensure_ranged!(Nanoseconds: nanosecond);
775 Ok(self)
776 }
777}
778
779#[cfg(feature = "formatting")]
780impl Time {
781 #[inline]
783 pub fn format_into(
784 self,
785 output: &mut (impl io::Write + ?Sized),
786 format: &(impl Formattable + ?Sized),
787 ) -> Result<usize, error::Format> {
788 format.format_into(output, None, Some(self), None)
789 }
790
791 #[inline]
801 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
802 format.format(None, Some(self), None)
803 }
804}
805
806#[cfg(feature = "parsing")]
807impl Time {
808 #[inline]
819 pub fn parse(
820 input: &str,
821 description: &(impl Parsable + ?Sized),
822 ) -> Result<Self, error::Parse> {
823 description.parse_time(input.as_bytes())
824 }
825}
826
827mod private {
828 #[non_exhaustive]
829 #[derive(#[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)]
830 pub struct TimeMetadata {
831 pub(super) subsecond_width: u8,
833 pub(super) subsecond_value: u32,
836 }
837}
838use private::TimeMetadata;
839
840impl SmartDisplay for Time {
841 type Metadata = TimeMetadata;
842
843 #[inline]
844 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
845 let (subsecond_value, subsecond_width) = match self.nanosecond() {
846 nanos if nanos % 10 != 0 => (nanos, 9),
847 nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
848 nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
849 nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
850 nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
851 nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
852 nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
853 nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
854 nanos => (nanos / 100_000_000, 1),
855 };
856
857 let formatted_width = 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!(
858 self.hour.get(),
859 ":",
860 self.minute.get() => width(2) fill('0'),
861 ":",
862 self.second.get() => width(2) fill('0'),
863 ".",
864 ) + subsecond_width;
865
866 Metadata::new(
867 formatted_width,
868 self,
869 TimeMetadata {
870 subsecond_width: subsecond_width.truncate(),
871 subsecond_value,
872 },
873 )
874 }
875
876 #[inline]
877 fn fmt_with_metadata(
878 &self,
879 f: &mut fmt::Formatter<'_>,
880 metadata: Metadata<Self>,
881 ) -> fmt::Result {
882 let subsecond_width = metadata.subsecond_width.extend();
883 let subsecond_value = metadata.subsecond_value;
884
885 f.pad_with_width(
886 metadata.unpadded_width(),
887 format_args!("{0}:{1:02}:{2:02}.{3:04$}", self.hour, self.minute, self.second,
subsecond_value, subsecond_width)format_args!(
888 "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
889 self.hour, self.minute, self.second
890 ),
891 )
892 }
893}
894
895impl fmt::Display for Time {
896 #[inline]
897 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
898 SmartDisplay::fmt(self, f)
899 }
900}
901
902impl fmt::Debug for Time {
903 #[inline]
904 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
905 fmt::Display::fmt(self, f)
906 }
907}
908
909impl Add<Duration> for Time {
910 type Output = Self;
911
912 #[inline]
921 fn add(self, duration: Duration) -> Self::Output {
922 self.adjusting_add(duration).1
923 }
924}
925
926impl Add<StdDuration> for Time {
927 type Output = Self;
928
929 #[inline]
938 fn add(self, duration: StdDuration) -> Self::Output {
939 self.adjusting_add_std(duration).1
940 }
941}
942
943#[allow(unused_qualifications)]
impl core::ops::AddAssign<StdDuration> for Time {
#[inline]
fn add_assign(&mut self, rhs: StdDuration) { *self = *self + rhs; }
}impl_add_assign!(Time: Duration, StdDuration);
944
945impl Sub<Duration> for Time {
946 type Output = Self;
947
948 #[inline]
957 fn sub(self, duration: Duration) -> Self::Output {
958 self.adjusting_sub(duration).1
959 }
960}
961
962impl Sub<StdDuration> for Time {
963 type Output = Self;
964
965 #[inline]
974 fn sub(self, duration: StdDuration) -> Self::Output {
975 self.adjusting_sub_std(duration).1
976 }
977}
978
979#[allow(unused_qualifications)]
impl core::ops::SubAssign<StdDuration> for Time {
#[inline]
fn sub_assign(&mut self, rhs: StdDuration) { *self = *self - rhs; }
}impl_sub_assign!(Time: Duration, StdDuration);
980
981impl Sub for Time {
982 type Output = Duration;
983
984 #[inline]
996 fn sub(self, rhs: Self) -> Self::Output {
997 let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
998 let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
999 let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
1000 let nanosecond_diff =
1001 self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
1002
1003 let seconds = hour_diff.extend::<i32>() * Second::per_t::<i32>(Hour)
1004 + minute_diff.extend::<i32>() * Second::per_t::<i32>(Minute)
1005 + second_diff.extend::<i32>();
1006
1007 let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
1008 (
1009 seconds - 1,
1010 nanosecond_diff + Nanosecond::per_t::<i32>(Second),
1011 )
1012 } else if seconds < 0 && nanosecond_diff > 0 {
1013 (
1014 seconds + 1,
1015 nanosecond_diff - Nanosecond::per_t::<i32>(Second),
1016 )
1017 } else {
1018 (seconds, nanosecond_diff)
1019 };
1020
1021 unsafe { Duration::new_unchecked(seconds.extend(), nanoseconds) }
1023 }
1024}