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::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/// By explicitly inserting this enum where padding is expected, the compiler is able to better
28/// perform niche value optimization.
29#[repr(u8)]
30#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub(crate) enum Padding {
32 #[allow(clippy::missing_docs_in_private_items)]
33 Optimize,
34}
35
36/// The type of the `hour` field of `Time`.
37type Hours = RangedU8<0, { Hour::per_t::<u8>(Day) - 1 }>;
38/// The type of the `minute` field of `Time`.
39type Minutes = RangedU8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
40/// The type of the `second` field of `Time`.
41type Seconds = RangedU8<0, { Second::per_t::<u8>(Minute) - 1 }>;
42/// The type of the `nanosecond` field of `Time`.
43type Nanoseconds = RangedU32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>;
44
45/// The clock time within a given date. Nanosecond precision.
46///
47/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
48/// (either positive or negative).
49///
50/// When comparing two `Time`s, they are assumed to be in the same calendar date.
51#[derive(Clone, Copy, Eq)]
52#[cfg_attr(not(docsrs), repr(C))]
53pub struct Time {
54 // The order of this struct's fields matter! Do not reorder them.
55
56 // Little endian version
57 #[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 // Big endian version
69 #[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 /// Provide a representation of `Time` as a `u64`. This value can be used for equality, hashing,
114 /// and ordering.
115 #[inline]
116 pub(crate) const fn as_u64(self) -> u64 {
117 // Safety: `self` is presumed valid because it exists, and any value of `u64` is valid. Size
118 // and alignment are enforced by the compiler. There is no implicit padding in either `Time`
119 // or `u64`.
120 unsafe { core::mem::transmute(self) }
121 }
122
123 /// A `Time` that is exactly midnight. This is the smallest possible value for a `Time`.
124 ///
125 /// ```rust
126 /// # use time::Time;
127 /// # use time_macros::time;
128 /// assert_eq!(Time::MIDNIGHT, time!(0:00));
129 /// ```
130 #[doc(alias = "MIN")]
131 pub const MIDNIGHT: Self =
132 Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
133
134 /// A `Time` that is one nanosecond before midnight. This is the largest possible value for a
135 /// `Time`.
136 ///
137 /// ```rust
138 /// # use time::Time;
139 /// # use time_macros::time;
140 /// assert_eq!(Time::MAX, time!(23:59:59.999_999_999));
141 /// ```
142 pub const MAX: Self =
143 Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
144
145 /// Create a `Time` from its components.
146 ///
147 /// # Safety
148 ///
149 /// - `hours` must be in the range `0..=23`.
150 /// - `minutes` must be in the range `0..=59`.
151 /// - `seconds` must be in the range `0..=59`.
152 /// - `nanoseconds` must be in the range `0..=999_999_999`.
153 #[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 // Safety: The caller must uphold the safety invariants.
163 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 /// Attempt to create a `Time` from the hour, minute, and second.
174 ///
175 /// ```rust
176 /// # use time::Time;
177 /// assert!(Time::from_hms(1, 2, 3).is_ok());
178 /// ```
179 ///
180 /// ```rust
181 /// # use time::Time;
182 /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
183 /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
184 /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
185 /// ```
186 #[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 ensure_ranged!(Hours: hour),
190 ensure_ranged!(Minutes: minute),
191 ensure_ranged!(Seconds: second),
192 Nanoseconds::MIN,
193 ))
194 }
195
196 /// Create a `Time` from the hour, minute, second, and nanosecond.
197 #[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 /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
214 ///
215 /// ```rust
216 /// # use time::Time;
217 /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
218 /// ```
219 ///
220 /// ```rust
221 /// # use time::Time;
222 /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
223 /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
224 /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
225 /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
226 /// ```
227 #[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 ensure_ranged!(Hours: hour),
236 ensure_ranged!(Minutes: minute),
237 ensure_ranged!(Seconds: second),
238 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)),
239 ))
240 }
241
242 /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
243 ///
244 /// ```rust
245 /// # use time::Time;
246 /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
247 /// ```
248 ///
249 /// ```rust
250 /// # use time::Time;
251 /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
252 /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
253 /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
254 /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
255 /// ```
256 #[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 ensure_ranged!(Hours: hour),
265 ensure_ranged!(Minutes: minute),
266 ensure_ranged!(Seconds: second),
267 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)),
268 ))
269 }
270
271 /// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
272 ///
273 /// ```rust
274 /// # use time::Time;
275 /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
276 /// ```
277 ///
278 /// ```rust
279 /// # use time::Time;
280 /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
281 /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
282 /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
283 /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
284 /// ```
285 #[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 ensure_ranged!(Hours: hour),
294 ensure_ranged!(Minutes: minute),
295 ensure_ranged!(Seconds: second),
296 ensure_ranged!(Nanoseconds: nanosecond),
297 ))
298 }
299
300 /// Get the clock hour, minute, and second.
301 ///
302 /// ```rust
303 /// # use time_macros::time;
304 /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
305 /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
306 /// ```
307 #[inline]
308 pub const fn as_hms(self) -> (u8, u8, u8) {
309 (self.hour.get(), self.minute.get(), self.second.get())
310 }
311
312 /// Get the clock hour, minute, second, and millisecond.
313 ///
314 /// ```rust
315 /// # use time_macros::time;
316 /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
317 /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
318 /// ```
319 #[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 /// Get the clock hour, minute, second, and microsecond.
330 ///
331 /// ```rust
332 /// # use time_macros::time;
333 /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
334 /// assert_eq!(
335 /// time!(23:59:59.999_999).as_hms_micro(),
336 /// (23, 59, 59, 999_999)
337 /// );
338 /// ```
339 #[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 /// Get the clock hour, minute, second, and nanosecond.
350 ///
351 /// ```rust
352 /// # use time_macros::time;
353 /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
354 /// assert_eq!(
355 /// time!(23:59:59.999_999_999).as_hms_nano(),
356 /// (23, 59, 59, 999_999_999)
357 /// );
358 /// ```
359 #[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 /// Get the clock hour, minute, second, and nanosecond.
370 #[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 /// Get the clock hour.
377 ///
378 /// The returned value will always be in the range `0..24`.
379 ///
380 /// ```rust
381 /// # use time_macros::time;
382 /// assert_eq!(time!(0:00:00).hour(), 0);
383 /// assert_eq!(time!(23:59:59).hour(), 23);
384 /// ```
385 #[inline]
386 pub const fn hour(self) -> u8 {
387 self.hour.get()
388 }
389
390 /// Get the minute within the hour.
391 ///
392 /// The returned value will always be in the range `0..60`.
393 ///
394 /// ```rust
395 /// # use time_macros::time;
396 /// assert_eq!(time!(0:00:00).minute(), 0);
397 /// assert_eq!(time!(23:59:59).minute(), 59);
398 /// ```
399 #[inline]
400 pub const fn minute(self) -> u8 {
401 self.minute.get()
402 }
403
404 /// Get the second within the minute.
405 ///
406 /// The returned value will always be in the range `0..60`.
407 ///
408 /// ```rust
409 /// # use time_macros::time;
410 /// assert_eq!(time!(0:00:00).second(), 0);
411 /// assert_eq!(time!(23:59:59).second(), 59);
412 /// ```
413 #[inline]
414 pub const fn second(self) -> u8 {
415 self.second.get()
416 }
417
418 /// Get the milliseconds within the second.
419 ///
420 /// The returned value will always be in the range `0..1_000`.
421 ///
422 /// ```rust
423 /// # use time_macros::time;
424 /// assert_eq!(time!(0:00).millisecond(), 0);
425 /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
426 /// ```
427 #[inline]
428 pub const fn millisecond(self) -> u16 {
429 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
430 }
431
432 /// Get the microseconds within the second.
433 ///
434 /// The returned value will always be in the range `0..1_000_000`.
435 ///
436 /// ```rust
437 /// # use time_macros::time;
438 /// assert_eq!(time!(0:00).microsecond(), 0);
439 /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
440 /// ```
441 #[inline]
442 pub const fn microsecond(self) -> u32 {
443 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
444 }
445
446 /// Get the nanoseconds within the second.
447 ///
448 /// The returned value will always be in the range `0..1_000_000_000`.
449 ///
450 /// ```rust
451 /// # use time_macros::time;
452 /// assert_eq!(time!(0:00).nanosecond(), 0);
453 /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
454 /// ```
455 #[inline]
456 pub const fn nanosecond(self) -> u32 {
457 self.nanosecond.get()
458 }
459
460 /// Determine the [`Duration`] that, if added to `self`, would result in the parameter.
461 ///
462 /// ```rust
463 /// # use time::Time;
464 /// # use time::ext::NumericalDuration;
465 /// # use time_macros::time;
466 /// assert_eq!(time!(18:00).duration_until(Time::MIDNIGHT), 6.hours());
467 /// assert_eq!(time!(23:00).duration_until(time!(1:00)), 2.hours());
468 /// ```
469 #[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 // Safety: For all four variables, the bounds are obviously true given the previous bounds
478 // and nature of subtraction.
479 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 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 // Safety: The range of `nanoseconds` is guaranteed by the cascades above.
519 unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) }
520 }
521
522 /// Determine the [`Duration`] that, if added to the parameter, would result in `self`.
523 ///
524 /// ```rust
525 /// # use time::Time;
526 /// # use time::ext::NumericalDuration;
527 /// # use time_macros::time;
528 /// assert_eq!(Time::MIDNIGHT.duration_since(time!(18:00)), 6.hours());
529 /// assert_eq!(time!(1:00).duration_since(time!(23:00)), 2.hours());
530 /// ```
531 #[inline]
532 pub const fn duration_since(self, other: Self) -> Duration {
533 other.duration_until(self)
534 }
535
536 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
537 /// the date is different.
538 #[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 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
550 cascade!(seconds in 0..Second::per_t(Minute) => minutes);
551 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 // Safety: The cascades above ensure the values are in range.
563 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 /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
575 /// whether the date is different.
576 #[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 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
588 cascade!(seconds in 0..Second::per_t(Minute) => minutes);
589 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 // Safety: The cascades above ensure the values are in range.
601 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 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
613 /// returning whether the date is the previous date as the first element of the tuple.
614 #[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 cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
627 cascade!(second in 0..Second::per_t(Minute) => minute);
628 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 // Safety: The cascades above ensure the values are in range.
637 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
638 )
639 }
640
641 /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
642 /// returning whether the date is the previous date as the first element of the tuple.
643 #[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 cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
657 cascade!(second in 0..Second::per_t(Minute) => minute);
658 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 // Safety: The cascades above ensure the values are in range.
667 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 /// Replace the clock hour.
679 ///
680 /// ```rust
681 /// # use time_macros::time;
682 /// assert_eq!(
683 /// time!(01:02:03.004_005_006).replace_hour(7),
684 /// Ok(time!(07:02:03.004_005_006))
685 /// );
686 /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
687 /// ```
688 #[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 = ensure_ranged!(Hours: hour);
692 Ok(self)
693 }
694
695 /// Truncate the time to the hour, setting the minute, second, and subsecond components to zero.
696 ///
697 /// ```rust
698 /// # use time_macros::time;
699 /// assert_eq!(time!(01:02:03.004_005_006).truncate_to_hour(), time!(01:00));
700 /// ```
701 #[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 /// Replace the minutes within the hour.
711 ///
712 /// ```rust
713 /// # use time_macros::time;
714 /// assert_eq!(
715 /// time!(01:02:03.004_005_006).replace_minute(7),
716 /// Ok(time!(01:07:03.004_005_006))
717 /// );
718 /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
719 /// ```
720 #[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 = ensure_ranged!(Minutes: minute);
724 Ok(self)
725 }
726
727 /// Truncate the time to the minute, setting the second and subsecond components to zero.
728 ///
729 /// ```rust
730 /// # use time_macros::time;
731 /// assert_eq!(
732 /// time!(01:02:03.004_005_006).truncate_to_minute(),
733 /// time!(01:02)
734 /// );
735 /// ```
736 #[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 /// Replace the seconds within the minute.
745 ///
746 /// ```rust
747 /// # use time_macros::time;
748 /// assert_eq!(
749 /// time!(01:02:03.004_005_006).replace_second(7),
750 /// Ok(time!(01:02:07.004_005_006))
751 /// );
752 /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
753 /// ```
754 #[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 = ensure_ranged!(Seconds: second);
758 Ok(self)
759 }
760
761 /// Truncate the time to the second, setting the subsecond component to zero.
762 ///
763 /// ```rust
764 /// # use time_macros::time;
765 /// assert_eq!(
766 /// time!(01:02:03.004_005_006).truncate_to_second(),
767 /// time!(01:02:03)
768 /// );
769 /// ```
770 #[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 /// Replace the milliseconds within the second.
778 ///
779 /// ```rust
780 /// # use time_macros::time;
781 /// assert_eq!(
782 /// time!(01:02:03.004_005_006).replace_millisecond(7),
783 /// Ok(time!(01:02:03.007))
784 /// );
785 /// assert!(
786 /// time!(01:02:03.004_005_006)
787 /// .replace_millisecond(1_000)
788 /// .is_err() // 1_000 isn't a valid millisecond
789 /// );
790 /// ```
791 #[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 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
799 Ok(self)
800 }
801
802 /// Truncate the time to the millisecond, setting the microsecond and nanosecond components to
803 /// zero.
804 ///
805 /// ```rust
806 /// # use time_macros::time;
807 /// assert_eq!(
808 /// time!(01:02:03.004_005_006).truncate_to_millisecond(),
809 /// time!(01:02:03.004)
810 /// );
811 /// ```
812 #[must_use = "This method does not mutate the original `Time`."]
813 #[inline]
814 pub const fn truncate_to_millisecond(mut self) -> Self {
815 // Safety: Truncating to the millisecond will always produce a valid nanosecond.
816 self.nanosecond = unsafe {
817 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000_000))
818 };
819 self
820 }
821
822 /// Replace the microseconds within the second.
823 ///
824 /// ```rust
825 /// # use time_macros::time;
826 /// assert_eq!(
827 /// time!(01:02:03.004_005_006).replace_microsecond(7_008),
828 /// Ok(time!(01:02:03.007_008))
829 /// );
830 /// assert!(
831 /// time!(01:02:03.004_005_006)
832 /// .replace_microsecond(1_000_000)
833 /// .is_err() // 1_000_000 isn't a valid microsecond
834 /// );
835 /// ```
836 #[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 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
844 Ok(self)
845 }
846
847 /// Truncate the time to the microsecond, setting the nanosecond component to zero.
848 ///
849 /// ```rust
850 /// # use time_macros::time;
851 /// assert_eq!(
852 /// time!(01:02:03.004_005_006).truncate_to_microsecond(),
853 /// time!(01:02:03.004_005)
854 /// );
855 /// ```
856 #[must_use = "This method does not mutate the original `Time`."]
857 #[inline]
858 pub const fn truncate_to_microsecond(mut self) -> Self {
859 // Safety: Truncating to the microsecond will always produce a valid nanosecond.
860 self.nanosecond = unsafe {
861 Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000))
862 };
863 self
864 }
865
866 /// Replace the nanoseconds within the second.
867 ///
868 /// ```rust
869 /// # use time_macros::time;
870 /// assert_eq!(
871 /// time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
872 /// Ok(time!(01:02:03.007_008_009))
873 /// );
874 /// assert!(
875 /// time!(01:02:03.004_005_006)
876 /// .replace_nanosecond(1_000_000_000)
877 /// .is_err() // 1_000_000_000 isn't a valid nanosecond
878 /// );
879 /// ```
880 #[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 = ensure_ranged!(Nanoseconds: nanosecond);
887 Ok(self)
888 }
889}
890
891#[cfg(feature = "formatting")]
892impl Time {
893 /// Format the `Time` using the provided [format description](crate::format_description).
894 #[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 /// Format the `Time` using the provided [format description](crate::format_description).
904 ///
905 /// ```rust
906 /// # use time::format_description;
907 /// # use time_macros::time;
908 /// let format = format_description::parse("[hour]:[minute]:[second]")?;
909 /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
910 /// # Ok::<_, time::Error>(())
911 /// ```
912 #[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 /// Parse a `Time` from the input using the provided [format
921 /// description](crate::format_description).
922 ///
923 /// ```rust
924 /// # use time::Time;
925 /// # use time_macros::{time, format_description};
926 /// let format = format_description!("[hour]:[minute]:[second]");
927 /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
928 /// # Ok::<_, time::Error>(())
929 /// ```
930 #[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 /// Metadata for `Time`.
941 #[non_exhaustive]
942 #[derive(Debug, Clone, Copy)]
943 pub struct TimeMetadata {
944 /// How many characters wide the formatted subsecond is.
945 pub(super) subsecond_width: u8,
946 /// The value to use when formatting the subsecond. Leading zeroes will be added as
947 /// necessary.
948 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 = 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!(
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 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
1026 ///
1027 /// ```rust
1028 /// # use time::ext::NumericalDuration;
1029 /// # use time_macros::time;
1030 /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
1031 /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
1032 /// ```
1033 #[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 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
1050 ///
1051 /// ```rust
1052 /// # use time::ext::NumericalStdDuration;
1053 /// # use time_macros::time;
1054 /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
1055 /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
1056 /// ```
1057 #[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 /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
1074 ///
1075 /// ```rust
1076 /// # use time::ext::NumericalDuration;
1077 /// # use time_macros::time;
1078 /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
1079 /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
1080 /// ```
1081 #[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 /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
1098 ///
1099 /// ```rust
1100 /// # use time::ext::NumericalStdDuration;
1101 /// # use time_macros::time;
1102 /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
1103 /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
1104 /// ```
1105 #[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 /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
1122 /// the same calendar day.
1123 ///
1124 /// ```rust
1125 /// # use time::ext::NumericalDuration;
1126 /// # use time_macros::time;
1127 /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
1128 /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
1129 /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
1130 /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
1131 /// ```
1132 #[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 // Safety: `nanoseconds` is in range due to the overflow handling.
1159 unsafe { Duration::new_unchecked(seconds.extend(), nanoseconds) }
1160 }
1161}