time/time.rs
1//! The [`Time`] struct and its associated `impl`s.
2
3#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::cmp::Ordering;
6use core::hash::{Hash, Hasher};
7use core::mem::MaybeUninit;
8use core::ops::{Add, AddAssign, Sub, SubAssign};
9use core::time::Duration as StdDuration;
10use core::{fmt, hint};
11#[cfg(feature = "formatting")]
12use std::io;
13
14use deranged::{ru8, ru32};
15use num_conv::prelude::*;
16use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
17
18#[cfg(feature = "formatting")]
19use crate::formatting::Formattable;
20use crate::internal_macros::{cascade, ensure_ranged};
21use crate::num_fmt::{
22 one_to_two_digits_no_padding, str_from_raw_parts, truncated_subsecond_from_nanos,
23 two_digits_zero_padded,
24};
25#[cfg(feature = "parsing")]
26use crate::parsing::Parsable;
27use crate::unit::*;
28use crate::util::DateAdjustment;
29use crate::{Duration, error};
30
31/// By explicitly inserting this enum where padding is expected, the compiler is able to better
32/// perform niche value optimization.
33#[repr(u8)]
34#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
35pub(crate) enum Padding {
36 #[allow(clippy::missing_docs_in_private_items)]
37 Optimize,
38}
39
40/// The type of the `hour` field of `Time`.
41pub(crate) type Hours = ru8<0, { Hour::per_t::<u8>(Day) - 1 }>;
42/// The type of the `minute` field of `Time`.
43pub(crate) type Minutes = ru8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
44/// The type of the `second` field of `Time`.
45pub(crate) type Seconds = ru8<0, { Second::per_t::<u8>(Minute) - 1 }>;
46/// The type of the `nanosecond` field of `Time`.
47pub(crate) type Nanoseconds = ru32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>;
48
49/// The clock time within a given date. Nanosecond precision.
50///
51/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
52/// (either positive or negative).
53///
54/// When comparing two `Time`s, they are assumed to be in the same calendar date.
55#[derive(Clone, Copy, Eq)]
56#[cfg_attr(not(docsrs), repr(C))]
57pub struct Time {
58 // The order of this struct's fields matter! Do not reorder them.
59
60 // Little endian version
61 #[cfg(target_endian = "little")]
62 nanosecond: Nanoseconds,
63 #[cfg(target_endian = "little")]
64 second: Seconds,
65 #[cfg(target_endian = "little")]
66 minute: Minutes,
67 #[cfg(target_endian = "little")]
68 hour: Hours,
69 #[cfg(target_endian = "little")]
70 padding: Padding,
71
72 // Big endian version
73 #[cfg(target_endian = "big")]
74 padding: Padding,
75 #[cfg(target_endian = "big")]
76 hour: Hours,
77 #[cfg(target_endian = "big")]
78 minute: Minutes,
79 #[cfg(target_endian = "big")]
80 second: Seconds,
81 #[cfg(target_endian = "big")]
82 nanosecond: Nanoseconds,
83}
84
85impl Hash for Time {
86 #[inline]
87 fn hash<H>(&self, state: &mut H)
88 where
89 H: Hasher,
90 {
91 self.as_u64().hash(state)
92 }
93}
94
95impl PartialEq for Time {
96 #[inline]
97 fn eq(&self, other: &Self) -> bool {
98 self.as_u64().eq(&other.as_u64())
99 }
100}
101
102impl PartialOrd for Time {
103 #[inline]
104 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
105 Some(self.cmp(other))
106 }
107}
108
109impl Ord for Time {
110 #[inline]
111 fn cmp(&self, other: &Self) -> Ordering {
112 self.as_u64().cmp(&other.as_u64())
113 }
114}
115
116impl Time {
117 /// Provide a representation of `Time` as a `u64`. This value can be used for equality, hashing,
118 /// and ordering.
119 #[inline]
120 pub(crate) const fn as_u64(self) -> u64 {
121 // Safety: `self` is presumed valid because it exists, and any value of `u64` is valid. Size
122 // and alignment are enforced by the compiler. There is no implicit padding in either `Time`
123 // or `u64`.
124 unsafe { core::mem::transmute(self) }
125 }
126
127 /// A `Time` that is exactly midnight. This is the smallest possible value for a `Time`.
128 ///
129 /// ```rust
130 /// # use time::Time;
131 /// # use time_macros::time;
132 /// assert_eq!(Time::MIDNIGHT, time!(0:00));
133 /// ```
134 #[doc(alias = "MIN")]
135 pub const MIDNIGHT: Self =
136 Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
137
138 /// A `Time` that is one nanosecond before midnight. This is the largest possible value for a
139 /// `Time`.
140 ///
141 /// ```rust
142 /// # use time::Time;
143 /// # use time_macros::time;
144 /// assert_eq!(Time::MAX, time!(23:59:59.999_999_999));
145 /// ```
146 pub const MAX: Self =
147 Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
148
149 /// Create a `Time` from its components.
150 ///
151 /// # Safety
152 ///
153 /// - `hours` must be in the range `0..=23`.
154 /// - `minutes` must be in the range `0..=59`.
155 /// - `seconds` must be in the range `0..=59`.
156 /// - `nanoseconds` must be in the range `0..=999_999_999`.
157 #[doc(hidden)]
158 #[inline]
159 #[track_caller]
160 pub const unsafe fn __from_hms_nanos_unchecked(
161 hour: u8,
162 minute: u8,
163 second: u8,
164 nanosecond: u32,
165 ) -> Self {
166 // Safety: The caller must uphold the safety invariants.
167 unsafe {
168 Self::from_hms_nanos_ranged(
169 Hours::new_unchecked(hour),
170 Minutes::new_unchecked(minute),
171 Seconds::new_unchecked(second),
172 Nanoseconds::new_unchecked(nanosecond),
173 )
174 }
175 }
176
177 /// Attempt to create a `Time` from the hour, minute, and second.
178 ///
179 /// ```rust
180 /// # use time::Time;
181 /// assert!(Time::from_hms(1, 2, 3).is_ok());
182 /// ```
183 ///
184 /// ```rust
185 /// # use time::Time;
186 /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
187 /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
188 /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
189 /// ```
190 #[inline]
191 pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
192 Ok(Self::from_hms_nanos_ranged(
193 ensure_ranged!(Hours: hour),
194 ensure_ranged!(Minutes: minute),
195 ensure_ranged!(Seconds: second),
196 Nanoseconds::MIN,
197 ))
198 }
199
200 /// Create a `Time` from the hour, minute, second, and nanosecond.
201 #[inline]
202 pub(crate) const fn from_hms_nanos_ranged(
203 hour: Hours,
204 minute: Minutes,
205 second: Seconds,
206 nanosecond: Nanoseconds,
207 ) -> Self {
208 Self {
209 hour,
210 minute,
211 second,
212 nanosecond,
213 padding: Padding::Optimize,
214 }
215 }
216
217 /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
218 ///
219 /// ```rust
220 /// # use time::Time;
221 /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
222 /// ```
223 ///
224 /// ```rust
225 /// # use time::Time;
226 /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
227 /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
228 /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
229 /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
230 /// ```
231 #[inline]
232 pub const fn from_hms_milli(
233 hour: u8,
234 minute: u8,
235 second: u8,
236 millisecond: u16,
237 ) -> Result<Self, error::ComponentRange> {
238 Ok(Self::from_hms_nanos_ranged(
239 ensure_ranged!(Hours: hour),
240 ensure_ranged!(Minutes: minute),
241 ensure_ranged!(Seconds: second),
242 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)),
243 ))
244 }
245
246 /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
247 ///
248 /// ```rust
249 /// # use time::Time;
250 /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
251 /// ```
252 ///
253 /// ```rust
254 /// # use time::Time;
255 /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
256 /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
257 /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
258 /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
259 /// ```
260 #[inline]
261 pub const fn from_hms_micro(
262 hour: u8,
263 minute: u8,
264 second: u8,
265 microsecond: u32,
266 ) -> Result<Self, error::ComponentRange> {
267 Ok(Self::from_hms_nanos_ranged(
268 ensure_ranged!(Hours: hour),
269 ensure_ranged!(Minutes: minute),
270 ensure_ranged!(Seconds: second),
271 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)),
272 ))
273 }
274
275 /// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
276 ///
277 /// ```rust
278 /// # use time::Time;
279 /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
280 /// ```
281 ///
282 /// ```rust
283 /// # use time::Time;
284 /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
285 /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
286 /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
287 /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
288 /// ```
289 #[inline]
290 pub const fn from_hms_nano(
291 hour: u8,
292 minute: u8,
293 second: u8,
294 nanosecond: u32,
295 ) -> Result<Self, error::ComponentRange> {
296 Ok(Self::from_hms_nanos_ranged(
297 ensure_ranged!(Hours: hour),
298 ensure_ranged!(Minutes: minute),
299 ensure_ranged!(Seconds: second),
300 ensure_ranged!(Nanoseconds: nanosecond),
301 ))
302 }
303
304 /// Get the clock hour, minute, and second.
305 ///
306 /// ```rust
307 /// # use time_macros::time;
308 /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
309 /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
310 /// ```
311 #[inline]
312 pub const fn as_hms(self) -> (u8, u8, u8) {
313 (self.hour.get(), self.minute.get(), self.second.get())
314 }
315
316 /// Get the clock hour, minute, second, and millisecond.
317 ///
318 /// ```rust
319 /// # use time_macros::time;
320 /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
321 /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
322 /// ```
323 #[inline]
324 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
325 (
326 self.hour.get(),
327 self.minute.get(),
328 self.second.get(),
329 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16,
330 )
331 }
332
333 /// Get the clock hour, minute, second, and microsecond.
334 ///
335 /// ```rust
336 /// # use time_macros::time;
337 /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
338 /// assert_eq!(
339 /// time!(23:59:59.999_999).as_hms_micro(),
340 /// (23, 59, 59, 999_999)
341 /// );
342 /// ```
343 #[inline]
344 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
345 (
346 self.hour.get(),
347 self.minute.get(),
348 self.second.get(),
349 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
350 )
351 }
352
353 /// Get the clock hour, minute, second, and nanosecond.
354 ///
355 /// ```rust
356 /// # use time_macros::time;
357 /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
358 /// assert_eq!(
359 /// time!(23:59:59.999_999_999).as_hms_nano(),
360 /// (23, 59, 59, 999_999_999)
361 /// );
362 /// ```
363 #[inline]
364 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
365 (
366 self.hour.get(),
367 self.minute.get(),
368 self.second.get(),
369 self.nanosecond.get(),
370 )
371 }
372
373 /// Get the clock hour, minute, second, and nanosecond.
374 #[inline]
375 #[cfg(any(feature = "formatting", feature = "quickcheck"))]
376 pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
377 (self.hour, self.minute, self.second, self.nanosecond)
378 }
379
380 /// Get the clock hour.
381 ///
382 /// The returned value will always be in the range `0..24`.
383 ///
384 /// ```rust
385 /// # use time_macros::time;
386 /// assert_eq!(time!(0:00:00).hour(), 0);
387 /// assert_eq!(time!(23:59:59).hour(), 23);
388 /// ```
389 #[inline]
390 pub const fn hour(self) -> u8 {
391 self.hour.get()
392 }
393
394 /// Get the minute within the hour.
395 ///
396 /// The returned value will always be in the range `0..60`.
397 ///
398 /// ```rust
399 /// # use time_macros::time;
400 /// assert_eq!(time!(0:00:00).minute(), 0);
401 /// assert_eq!(time!(23:59:59).minute(), 59);
402 /// ```
403 #[inline]
404 pub const fn minute(self) -> u8 {
405 self.minute.get()
406 }
407
408 /// Get the second within the minute.
409 ///
410 /// The returned value will always be in the range `0..60`.
411 ///
412 /// ```rust
413 /// # use time_macros::time;
414 /// assert_eq!(time!(0:00:00).second(), 0);
415 /// assert_eq!(time!(23:59:59).second(), 59);
416 /// ```
417 #[inline]
418 pub const fn second(self) -> u8 {
419 self.second.get()
420 }
421
422 /// Get the milliseconds within the second.
423 ///
424 /// The returned value will always be in the range `0..1_000`.
425 ///
426 /// ```rust
427 /// # use time_macros::time;
428 /// assert_eq!(time!(0:00).millisecond(), 0);
429 /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
430 /// ```
431 #[inline]
432 pub const fn millisecond(self) -> u16 {
433 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
434 }
435
436 /// Get the microseconds within the second.
437 ///
438 /// The returned value will always be in the range `0..1_000_000`.
439 ///
440 /// ```rust
441 /// # use time_macros::time;
442 /// assert_eq!(time!(0:00).microsecond(), 0);
443 /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
444 /// ```
445 #[inline]
446 pub const fn microsecond(self) -> u32 {
447 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
448 }
449
450 /// Get the nanoseconds within the second.
451 ///
452 /// The returned value will always be in the range `0..1_000_000_000`.
453 ///
454 /// ```rust
455 /// # use time_macros::time;
456 /// assert_eq!(time!(0:00).nanosecond(), 0);
457 /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
458 /// ```
459 #[inline]
460 pub const fn nanosecond(self) -> u32 {
461 self.nanosecond.get()
462 }
463
464 /// Determine the [`Duration`] that, if added to `self`, would result in the parameter.
465 ///
466 /// ```rust
467 /// # use time::Time;
468 /// # use time::ext::NumericalDuration;
469 /// # use time_macros::time;
470 /// assert_eq!(time!(18:00).duration_until(Time::MIDNIGHT), 6.hours());
471 /// assert_eq!(time!(23:00).duration_until(time!(1:00)), 2.hours());
472 /// ```
473 #[inline]
474 pub const fn duration_until(self, other: Self) -> Duration {
475 let mut nanoseconds =
476 other.nanosecond.get().cast_signed() - self.nanosecond.get().cast_signed();
477 let seconds = other.second.get().cast_signed() - self.second.get().cast_signed();
478 let minutes = other.minute.get().cast_signed() - self.minute.get().cast_signed();
479 let hours = other.hour.get().cast_signed() - self.hour.get().cast_signed();
480
481 // Safety: For all four variables, the bounds are obviously true given the previous bounds
482 // and nature of subtraction.
483 unsafe {
484 hint::assert_unchecked(
485 nanoseconds
486 >= Nanoseconds::MIN.get().cast_signed() - Nanoseconds::MAX.get().cast_signed(),
487 );
488 hint::assert_unchecked(
489 nanoseconds
490 <= Nanoseconds::MAX.get().cast_signed() - Nanoseconds::MIN.get().cast_signed(),
491 );
492 hint::assert_unchecked(
493 seconds >= Seconds::MIN.get().cast_signed() - Seconds::MAX.get().cast_signed(),
494 );
495 hint::assert_unchecked(
496 seconds <= Seconds::MAX.get().cast_signed() - Seconds::MIN.get().cast_signed(),
497 );
498 hint::assert_unchecked(
499 minutes >= Minutes::MIN.get().cast_signed() - Minutes::MAX.get().cast_signed(),
500 );
501 hint::assert_unchecked(
502 minutes <= Minutes::MAX.get().cast_signed() - Minutes::MIN.get().cast_signed(),
503 );
504 hint::assert_unchecked(
505 hours >= Hours::MIN.get().cast_signed() - Hours::MAX.get().cast_signed(),
506 );
507 hint::assert_unchecked(
508 hours <= Hours::MAX.get().cast_signed() - Hours::MIN.get().cast_signed(),
509 );
510 }
511
512 let mut total_seconds = hours as i32 * Second::per_t::<i32>(Hour)
513 + minutes as i32 * Second::per_t::<i32>(Minute)
514 + seconds as i32;
515
516 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => total_seconds);
517
518 if total_seconds < 0 {
519 total_seconds += Second::per_t::<i32>(Day);
520 }
521
522 // Safety: The range of `nanoseconds` is guaranteed by the cascades above.
523 unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) }
524 }
525
526 /// Determine the [`Duration`] that, if added to the parameter, would result in `self`.
527 ///
528 /// ```rust
529 /// # use time::Time;
530 /// # use time::ext::NumericalDuration;
531 /// # use time_macros::time;
532 /// assert_eq!(Time::MIDNIGHT.duration_since(time!(18:00)), 6.hours());
533 /// assert_eq!(time!(1:00).duration_since(time!(23:00)), 2.hours());
534 /// ```
535 #[inline]
536 pub const fn duration_since(self, other: Self) -> Duration {
537 other.duration_until(self)
538 }
539
540 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
541 /// the date is different.
542 #[inline]
543 pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
544 let mut nanoseconds = self.nanosecond.get().cast_signed() + duration.subsec_nanoseconds();
545 let mut seconds = self.second.get().cast_signed()
546 + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
547 let mut minutes = self.minute.get().cast_signed()
548 + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
549 let mut hours = self.hour.get().cast_signed()
550 + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
551 let mut date_adjustment = DateAdjustment::None;
552
553 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
554 cascade!(seconds in 0..Second::per_t(Minute) => minutes);
555 cascade!(minutes in 0..Minute::per_t(Hour) => hours);
556 if hours >= Hour::per_t(Day) {
557 hours -= Hour::per_t::<i8>(Day);
558 date_adjustment = DateAdjustment::Next;
559 } else if hours < 0 {
560 hours += Hour::per_t::<i8>(Day);
561 date_adjustment = DateAdjustment::Previous;
562 }
563
564 (
565 date_adjustment,
566 // Safety: The cascades above ensure the values are in range.
567 unsafe {
568 Self::__from_hms_nanos_unchecked(
569 hours.cast_unsigned(),
570 minutes.cast_unsigned(),
571 seconds.cast_unsigned(),
572 nanoseconds.cast_unsigned(),
573 )
574 },
575 )
576 }
577
578 /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
579 /// whether the date is different.
580 #[inline]
581 pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
582 let mut nanoseconds = self.nanosecond.get().cast_signed() - duration.subsec_nanoseconds();
583 let mut seconds = self.second.get().cast_signed()
584 - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
585 let mut minutes = self.minute.get().cast_signed()
586 - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
587 let mut hours = self.hour.get().cast_signed()
588 - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
589 let mut date_adjustment = DateAdjustment::None;
590
591 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
592 cascade!(seconds in 0..Second::per_t(Minute) => minutes);
593 cascade!(minutes in 0..Minute::per_t(Hour) => hours);
594 if hours >= Hour::per_t(Day) {
595 hours -= Hour::per_t::<i8>(Day);
596 date_adjustment = DateAdjustment::Next;
597 } else if hours < 0 {
598 hours += Hour::per_t::<i8>(Day);
599 date_adjustment = DateAdjustment::Previous;
600 }
601
602 (
603 date_adjustment,
604 // Safety: The cascades above ensure the values are in range.
605 unsafe {
606 Self::__from_hms_nanos_unchecked(
607 hours.cast_unsigned(),
608 minutes.cast_unsigned(),
609 seconds.cast_unsigned(),
610 nanoseconds.cast_unsigned(),
611 )
612 },
613 )
614 }
615
616 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
617 /// returning whether the date is the previous date as the first element of the tuple.
618 #[inline]
619 pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
620 let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
621 let mut second =
622 self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
623 let mut minute = self.minute.get()
624 + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
625 as u8;
626 let mut hour = self.hour.get()
627 + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
628 let mut is_next_day = false;
629
630 cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
631 cascade!(second in 0..Second::per_t(Minute) => minute);
632 cascade!(minute in 0..Minute::per_t(Hour) => hour);
633 if hour >= Hour::per_t::<u8>(Day) {
634 hour -= Hour::per_t::<u8>(Day);
635 is_next_day = true;
636 }
637
638 (
639 is_next_day,
640 // Safety: The cascades above ensure the values are in range.
641 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
642 )
643 }
644
645 /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
646 /// returning whether the date is the previous date as the first element of the tuple.
647 #[inline]
648 pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
649 let mut nanosecond =
650 self.nanosecond.get().cast_signed() - duration.subsec_nanos().cast_signed();
651 let mut second = self.second.get().cast_signed()
652 - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
653 let mut minute = self.minute.get().cast_signed()
654 - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
655 as i8;
656 let mut hour = self.hour.get().cast_signed()
657 - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
658 let mut is_previous_day = false;
659
660 cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
661 cascade!(second in 0..Second::per_t(Minute) => minute);
662 cascade!(minute in 0..Minute::per_t(Hour) => hour);
663 if hour < 0 {
664 hour += Hour::per_t::<i8>(Day);
665 is_previous_day = true;
666 }
667
668 (
669 is_previous_day,
670 // Safety: The cascades above ensure the values are in range.
671 unsafe {
672 Self::__from_hms_nanos_unchecked(
673 hour.cast_unsigned(),
674 minute.cast_unsigned(),
675 second.cast_unsigned(),
676 nanosecond.cast_unsigned(),
677 )
678 },
679 )
680 }
681
682 /// Replace the clock hour.
683 ///
684 /// ```rust
685 /// # use time_macros::time;
686 /// assert_eq!(
687 /// time!(01:02:03.004_005_006).replace_hour(7),
688 /// Ok(time!(07:02:03.004_005_006))
689 /// );
690 /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
691 /// ```
692 #[must_use = "This method does not mutate the original `Time`."]
693 #[inline]
694 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
695 self.hour = ensure_ranged!(Hours: hour);
696 Ok(self)
697 }
698
699 /// Truncate the time to the hour, setting the minute, second, and subsecond components to zero.
700 ///
701 /// ```rust
702 /// # use time_macros::time;
703 /// assert_eq!(time!(01:02:03.004_005_006).truncate_to_hour(), time!(01:00));
704 /// ```
705 #[must_use = "This method does not mutate the original `Time`."]
706 #[inline]
707 pub const fn truncate_to_hour(mut self) -> Self {
708 self.minute = Minutes::MIN;
709 self.second = Seconds::MIN;
710 self.nanosecond = Nanoseconds::MIN;
711 self
712 }
713
714 /// Replace the minutes within the hour.
715 ///
716 /// ```rust
717 /// # use time_macros::time;
718 /// assert_eq!(
719 /// time!(01:02:03.004_005_006).replace_minute(7),
720 /// Ok(time!(01:07:03.004_005_006))
721 /// );
722 /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
723 /// ```
724 #[must_use = "This method does not mutate the original `Time`."]
725 #[inline]
726 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
727 self.minute = ensure_ranged!(Minutes: minute);
728 Ok(self)
729 }
730
731 /// Truncate the time to the minute, setting the second and subsecond components to zero.
732 ///
733 /// ```rust
734 /// # use time_macros::time;
735 /// assert_eq!(
736 /// time!(01:02:03.004_005_006).truncate_to_minute(),
737 /// time!(01:02)
738 /// );
739 /// ```
740 #[must_use = "This method does not mutate the original `Time`."]
741 #[inline]
742 pub const fn truncate_to_minute(mut self) -> Self {
743 self.second = Seconds::MIN;
744 self.nanosecond = Nanoseconds::MIN;
745 self
746 }
747
748 /// Replace the seconds within the minute.
749 ///
750 /// ```rust
751 /// # use time_macros::time;
752 /// assert_eq!(
753 /// time!(01:02:03.004_005_006).replace_second(7),
754 /// Ok(time!(01:02:07.004_005_006))
755 /// );
756 /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
757 /// ```
758 #[must_use = "This method does not mutate the original `Time`."]
759 #[inline]
760 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
761 self.second = ensure_ranged!(Seconds: second);
762 Ok(self)
763 }
764
765 /// Truncate the time to the second, setting the subsecond component to zero.
766 ///
767 /// ```rust
768 /// # use time_macros::time;
769 /// assert_eq!(
770 /// time!(01:02:03.004_005_006).truncate_to_second(),
771 /// time!(01:02:03)
772 /// );
773 /// ```
774 #[must_use = "This method does not mutate the original `Time`."]
775 #[inline]
776 pub const fn truncate_to_second(mut self) -> Self {
777 self.nanosecond = Nanoseconds::MIN;
778 self
779 }
780
781 /// Replace the milliseconds within the second.
782 ///
783 /// ```rust
784 /// # use time_macros::time;
785 /// assert_eq!(
786 /// time!(01:02:03.004_005_006).replace_millisecond(7),
787 /// Ok(time!(01:02:03.007))
788 /// );
789 /// assert!(
790 /// time!(01:02:03.004_005_006)
791 /// .replace_millisecond(1_000)
792 /// .is_err() // 1_000 isn't a valid millisecond
793 /// );
794 /// ```
795 #[must_use = "This method does not mutate the original `Time`."]
796 #[inline]
797 pub const fn replace_millisecond(
798 mut self,
799 millisecond: u16,
800 ) -> Result<Self, error::ComponentRange> {
801 self.nanosecond =
802 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
803 Ok(self)
804 }
805
806 /// Truncate the time to the millisecond, setting the microsecond and nanosecond components to
807 /// zero.
808 ///
809 /// ```rust
810 /// # use time_macros::time;
811 /// assert_eq!(
812 /// time!(01:02:03.004_005_006).truncate_to_millisecond(),
813 /// time!(01:02:03.004)
814 /// );
815 /// ```
816 #[must_use = "This method does not mutate the original `Time`."]
817 #[inline]
818 pub const fn truncate_to_millisecond(mut self) -> Self {
819 // Safety: Truncating to the millisecond will always produce a valid nanosecond.
820 self.nanosecond = unsafe {
821 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000_000))
822 };
823 self
824 }
825
826 /// Replace the microseconds within the second.
827 ///
828 /// ```rust
829 /// # use time_macros::time;
830 /// assert_eq!(
831 /// time!(01:02:03.004_005_006).replace_microsecond(7_008),
832 /// Ok(time!(01:02:03.007_008))
833 /// );
834 /// assert!(
835 /// time!(01:02:03.004_005_006)
836 /// .replace_microsecond(1_000_000)
837 /// .is_err() // 1_000_000 isn't a valid microsecond
838 /// );
839 /// ```
840 #[must_use = "This method does not mutate the original `Time`."]
841 #[inline]
842 pub const fn replace_microsecond(
843 mut self,
844 microsecond: u32,
845 ) -> Result<Self, error::ComponentRange> {
846 self.nanosecond =
847 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
848 Ok(self)
849 }
850
851 /// Truncate the time to the microsecond, setting the nanosecond component to zero.
852 ///
853 /// ```rust
854 /// # use time_macros::time;
855 /// assert_eq!(
856 /// time!(01:02:03.004_005_006).truncate_to_microsecond(),
857 /// time!(01:02:03.004_005)
858 /// );
859 /// ```
860 #[must_use = "This method does not mutate the original `Time`."]
861 #[inline]
862 pub const fn truncate_to_microsecond(mut self) -> Self {
863 // Safety: Truncating to the microsecond will always produce a valid nanosecond.
864 self.nanosecond = unsafe {
865 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000))
866 };
867 self
868 }
869
870 /// Replace the nanoseconds within the second.
871 ///
872 /// ```rust
873 /// # use time_macros::time;
874 /// assert_eq!(
875 /// time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
876 /// Ok(time!(01:02:03.007_008_009))
877 /// );
878 /// assert!(
879 /// time!(01:02:03.004_005_006)
880 /// .replace_nanosecond(1_000_000_000)
881 /// .is_err() // 1_000_000_000 isn't a valid nanosecond
882 /// );
883 /// ```
884 #[must_use = "This method does not mutate the original `Time`."]
885 #[inline]
886 pub const fn replace_nanosecond(
887 mut self,
888 nanosecond: u32,
889 ) -> Result<Self, error::ComponentRange> {
890 self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
891 Ok(self)
892 }
893}
894
895#[cfg(feature = "formatting")]
896impl Time {
897 /// Format the `Time` using the provided [format description](crate::format_description).
898 #[inline]
899 pub fn format_into(
900 self,
901 output: &mut (impl io::Write + ?Sized),
902 format: &(impl Formattable + ?Sized),
903 ) -> Result<usize, error::Format> {
904 format.format_into(output, &self, &mut Default::default())
905 }
906
907 /// Format the `Time` using the provided [format description](crate::format_description).
908 ///
909 /// ```rust
910 /// # use time::format_description;
911 /// # use time_macros::time;
912 /// let format = format_description::parse("[hour]:[minute]:[second]")?;
913 /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
914 /// # Ok::<_, time::Error>(())
915 /// ```
916 #[inline]
917 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
918 format.format(&self, &mut Default::default())
919 }
920}
921
922#[cfg(feature = "parsing")]
923impl Time {
924 /// Parse a `Time` from the input using the provided [format
925 /// description](crate::format_description).
926 ///
927 /// ```rust
928 /// # use time::Time;
929 /// # use time_macros::{time, format_description};
930 /// let format = format_description!("[hour]:[minute]:[second]");
931 /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
932 /// # Ok::<_, time::Error>(())
933 /// ```
934 #[inline]
935 pub fn parse(
936 input: &str,
937 description: &(impl Parsable + ?Sized),
938 ) -> Result<Self, error::Parse> {
939 description.parse_time(input.as_bytes())
940 }
941}
942
943mod private {
944 /// Metadata for `Time`.
945 #[non_exhaustive]
946 #[derive(Debug)]
947 pub struct TimeMetadata;
948}
949use private::TimeMetadata;
950
951// This no longer needs special handling, as the format is fixed and doesn't require anything
952// advanced. Trait impls can't be deprecated and the info is still useful for other types
953// implementing `SmartDisplay`, so leave it as-is for now.
954impl SmartDisplay for Time {
955 type Metadata = TimeMetadata;
956
957 #[inline]
958 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
959 let hour_width = if self.hour() < 10 { 1 } else { 2 };
960 let subsecond_width = match self.nanosecond() {
961 nanos if nanos % 10 != 0 => 9,
962 nanos if (nanos / 10) % 10 != 0 => 8,
963 nanos if (nanos / 100) % 10 != 0 => 7,
964 nanos if (nanos / 1_000) % 10 != 0 => 6,
965 nanos if (nanos / 10_000) % 10 != 0 => 5,
966 nanos if (nanos / 100_000) % 10 != 0 => 4,
967 nanos if (nanos / 1_000_000) % 10 != 0 => 3,
968 nanos if (nanos / 10_000_000) % 10 != 0 => 2,
969 _ => 1,
970 };
971 let total_width = hour_width + subsecond_width + 7;
972
973 Metadata::new(total_width, self, TimeMetadata)
974 }
975
976 #[inline]
977 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
978 fmt::Display::fmt(self, f)
979 }
980}
981
982impl Time {
983 /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used
984 /// for the `Display` implementation.
985 pub(crate) const DISPLAY_BUFFER_SIZE: usize = 18;
986
987 /// Format the `Time` into the provided buffer, returning the number of bytes written.
988 #[inline]
989 pub(crate) fn fmt_into_buffer(
990 self,
991 buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
992 ) -> usize {
993 let mut idx = 0;
994
995 // Safety: `self.hour()` is in the range required by its type.
996 let hour =
997 one_to_two_digits_no_padding(unsafe { Hours::new_unchecked(self.hour()) }.expand());
998 // Safety:
999 // - both `hour` and `buf` are valid for reads and writes of up to 2 bytes.
1000 // - `u8` is 1-aligned, so that is not a concern.
1001 // - `hour` points to static memory, while `buf` is a local variable, so they do not
1002 // overlap.
1003 unsafe {
1004 hour.as_ptr()
1005 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), hour.len())
1006 };
1007 idx += hour.len();
1008
1009 buf[idx] = MaybeUninit::new(b':');
1010 idx += 1;
1011
1012 // Safety: See above.
1013 unsafe {
1014 two_digits_zero_padded(Minutes::new_unchecked(self.minute()).expand())
1015 .as_ptr()
1016 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2)
1017 };
1018 idx += 2;
1019
1020 buf[idx] = MaybeUninit::new(b':');
1021 idx += 1;
1022
1023 // Safety: See above.
1024 unsafe {
1025 two_digits_zero_padded(Seconds::new_unchecked(self.second()).expand())
1026 .as_ptr()
1027 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2)
1028 };
1029 idx += 2;
1030
1031 buf[idx] = MaybeUninit::new(b'.');
1032 idx += 1;
1033
1034 // Safety: `self.nanosecond()` is guaranteed to be less than 1,000,000,000.
1035 let subsecond = truncated_subsecond_from_nanos(unsafe {
1036 Nanoseconds::new_unchecked(self.nanosecond())
1037 });
1038 // Safety: See above, except `subsecond` is valid for 9 bytes.
1039 unsafe {
1040 subsecond
1041 .as_ptr()
1042 .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len())
1043 };
1044 idx += subsecond.len();
1045
1046 idx
1047 }
1048}
1049
1050impl fmt::Display for Time {
1051 #[inline]
1052 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1053 let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1054 let len = self.fmt_into_buffer(&mut buf);
1055 // Safety: All bytes up to `len` have been initialized with ASCII characters.
1056 let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1057 f.pad(s)
1058 }
1059}
1060
1061impl fmt::Debug for Time {
1062 #[inline]
1063 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1064 fmt::Display::fmt(self, f)
1065 }
1066}
1067
1068impl Add<Duration> for Time {
1069 type Output = Self;
1070
1071 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
1072 ///
1073 /// ```rust
1074 /// # use time::ext::NumericalDuration;
1075 /// # use time_macros::time;
1076 /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
1077 /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
1078 /// ```
1079 #[inline]
1080 fn add(self, duration: Duration) -> Self::Output {
1081 self.adjusting_add(duration).1
1082 }
1083}
1084
1085impl AddAssign<Duration> for Time {
1086 #[inline]
1087 fn add_assign(&mut self, rhs: Duration) {
1088 *self = *self + rhs;
1089 }
1090}
1091
1092impl Add<StdDuration> for Time {
1093 type Output = Self;
1094
1095 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
1096 ///
1097 /// ```rust
1098 /// # use time::ext::NumericalStdDuration;
1099 /// # use time_macros::time;
1100 /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
1101 /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
1102 /// ```
1103 #[inline]
1104 fn add(self, duration: StdDuration) -> Self::Output {
1105 self.adjusting_add_std(duration).1
1106 }
1107}
1108
1109impl AddAssign<StdDuration> for Time {
1110 #[inline]
1111 fn add_assign(&mut self, rhs: StdDuration) {
1112 *self = *self + rhs;
1113 }
1114}
1115
1116impl Sub<Duration> for Time {
1117 type Output = Self;
1118
1119 /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
1120 ///
1121 /// ```rust
1122 /// # use time::ext::NumericalDuration;
1123 /// # use time_macros::time;
1124 /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
1125 /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
1126 /// ```
1127 #[inline]
1128 fn sub(self, duration: Duration) -> Self::Output {
1129 self.adjusting_sub(duration).1
1130 }
1131}
1132
1133impl SubAssign<Duration> for Time {
1134 #[inline]
1135 fn sub_assign(&mut self, rhs: Duration) {
1136 *self = *self - rhs;
1137 }
1138}
1139
1140impl Sub<StdDuration> for Time {
1141 type Output = Self;
1142
1143 /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
1144 ///
1145 /// ```rust
1146 /// # use time::ext::NumericalStdDuration;
1147 /// # use time_macros::time;
1148 /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
1149 /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
1150 /// ```
1151 #[inline]
1152 fn sub(self, duration: StdDuration) -> Self::Output {
1153 self.adjusting_sub_std(duration).1
1154 }
1155}
1156
1157impl SubAssign<StdDuration> for Time {
1158 #[inline]
1159 fn sub_assign(&mut self, rhs: StdDuration) {
1160 *self = *self - rhs;
1161 }
1162}
1163
1164impl Sub for Time {
1165 type Output = Duration;
1166
1167 /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
1168 /// the same calendar day.
1169 ///
1170 /// ```rust
1171 /// # use time::ext::NumericalDuration;
1172 /// # use time_macros::time;
1173 /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
1174 /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
1175 /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
1176 /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
1177 /// ```
1178 #[inline]
1179 fn sub(self, rhs: Self) -> Self::Output {
1180 let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
1181 let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
1182 let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
1183 let nanosecond_diff =
1184 self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
1185
1186 let seconds = hour_diff.extend::<i32>() * Second::per_t::<i32>(Hour)
1187 + minute_diff.extend::<i32>() * Second::per_t::<i32>(Minute)
1188 + second_diff.extend::<i32>();
1189
1190 let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
1191 (
1192 seconds - 1,
1193 nanosecond_diff + Nanosecond::per_t::<i32>(Second),
1194 )
1195 } else if seconds < 0 && nanosecond_diff > 0 {
1196 (
1197 seconds + 1,
1198 nanosecond_diff - Nanosecond::per_t::<i32>(Second),
1199 )
1200 } else {
1201 (seconds, nanosecond_diff)
1202 };
1203
1204 // Safety: `nanoseconds` is in range due to the overflow handling.
1205 unsafe { Duration::new_unchecked(seconds.extend(), nanoseconds) }
1206 }
1207}