time/time.rs
1//! The [`Time`] struct and its associated `impl`s.
2
3#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::fmt;
6use core::ops::{Add, Sub};
7use core::time::Duration as StdDuration;
8#[cfg(feature = "formatting")]
9use std::io;
10
11use deranged::{RangedU32, RangedU8};
12use num_conv::prelude::*;
13use powerfmt::ext::FormatterExt;
14use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
15
16use crate::convert::*;
17#[cfg(feature = "formatting")]
18use crate::formatting::Formattable;
19use crate::internal_macros::{cascade, ensure_ranged, impl_add_assign, impl_sub_assign};
20#[cfg(feature = "parsing")]
21use crate::parsing::Parsable;
22use crate::util::DateAdjustment;
23use crate::{error, hint, Duration};
24
25/// By explicitly inserting this enum where padding is expected, the compiler is able to better
26/// perform niche value optimization.
27#[repr(u8)]
28#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub(crate) enum Padding {
30 #[allow(clippy::missing_docs_in_private_items)]
31 Optimize,
32}
33
34/// The type of the `hour` field of `Time`.
35type Hours = RangedU8<0, { Hour::per_t::<u8>(Day) - 1 }>;
36/// The type of the `minute` field of `Time`.
37type Minutes = RangedU8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
38/// The type of the `second` field of `Time`.
39type Seconds = RangedU8<0, { Second::per_t::<u8>(Minute) - 1 }>;
40/// The type of the `nanosecond` field of `Time`.
41type Nanoseconds = RangedU32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>;
42
43/// The clock time within a given date. Nanosecond precision.
44///
45/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
46/// (either positive or negative).
47///
48/// When comparing two `Time`s, they are assumed to be in the same calendar date.
49#[derive(Clone, Copy, Eq)]
50#[repr(C)]
51pub struct Time {
52 // The order of this struct's fields matter!
53 // Do not change them.
54
55 // Little endian version
56 #[cfg(target_endian = "little")]
57 nanosecond: Nanoseconds,
58 #[cfg(target_endian = "little")]
59 second: Seconds,
60 #[cfg(target_endian = "little")]
61 minute: Minutes,
62 #[cfg(target_endian = "little")]
63 hour: Hours,
64 #[cfg(target_endian = "little")]
65 padding: Padding,
66
67 // Big endian version
68 #[cfg(target_endian = "big")]
69 padding: Padding,
70 #[cfg(target_endian = "big")]
71 hour: Hours,
72 #[cfg(target_endian = "big")]
73 minute: Minutes,
74 #[cfg(target_endian = "big")]
75 second: Seconds,
76 #[cfg(target_endian = "big")]
77 nanosecond: Nanoseconds,
78}
79
80impl core::hash::Hash for Time {
81 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
82 self.as_u64().hash(state)
83 }
84}
85
86impl PartialEq for Time {
87 fn eq(&self, other: &Self) -> bool {
88 self.as_u64().eq(&other.as_u64())
89 }
90}
91
92impl PartialOrd for Time {
93 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
94 Some(self.cmp(other))
95 }
96}
97
98impl Ord for Time {
99 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
100 self.as_u64().cmp(&other.as_u64())
101 }
102}
103
104impl Time {
105 /// Provides an u64 based representation **of the correct endianness**
106 ///
107 /// This representation can be used to do comparisons equality testing or hashing.
108 const fn as_u64(self) -> u64 {
109 let nano_bytes = self.nanosecond.get().to_ne_bytes();
110
111 #[cfg(target_endian = "big")]
112 return u64::from_be_bytes([
113 self.padding as u8,
114 self.hour.get(),
115 self.minute.get(),
116 self.second.get(),
117 nano_bytes[0],
118 nano_bytes[1],
119 nano_bytes[2],
120 nano_bytes[3],
121 ]);
122
123 #[cfg(target_endian = "little")]
124 return u64::from_le_bytes([
125 nano_bytes[0],
126 nano_bytes[1],
127 nano_bytes[2],
128 nano_bytes[3],
129 self.second.get(),
130 self.minute.get(),
131 self.hour.get(),
132 self.padding as u8,
133 ]);
134 }
135
136 /// A `Time` that is exactly midnight. This is the smallest possible value for a `Time`.
137 ///
138 /// ```rust
139 /// # use time::Time;
140 /// # use time_macros::time;
141 /// assert_eq!(Time::MIDNIGHT, time!(0:00));
142 /// ```
143 #[doc(alias = "MIN")]
144 pub const MIDNIGHT: Self =
145 Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
146
147 /// A `Time` that is one nanosecond before midnight. This is the largest possible value for a
148 /// `Time`.
149 ///
150 /// ```rust
151 /// # use time::Time;
152 /// # use time_macros::time;
153 /// assert_eq!(Time::MAX, time!(23:59:59.999_999_999));
154 /// ```
155 pub const MAX: Self =
156 Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
157
158 /// Create a `Time` from its components.
159 ///
160 /// # Safety
161 ///
162 /// - `hours` must be in the range `0..=23`.
163 /// - `minutes` must be in the range `0..=59`.
164 /// - `seconds` must be in the range `0..=59`.
165 /// - `nanoseconds` must be in the range `0..=999_999_999`.
166 #[doc(hidden)]
167 pub const unsafe fn __from_hms_nanos_unchecked(
168 hour: u8,
169 minute: u8,
170 second: u8,
171 nanosecond: u32,
172 ) -> Self {
173 // Safety: The caller must uphold the safety invariants.
174 unsafe {
175 Self::from_hms_nanos_ranged(
176 Hours::new_unchecked(hour),
177 Minutes::new_unchecked(minute),
178 Seconds::new_unchecked(second),
179 Nanoseconds::new_unchecked(nanosecond),
180 )
181 }
182 }
183
184 /// Attempt to create a `Time` from the hour, minute, and second.
185 ///
186 /// ```rust
187 /// # use time::Time;
188 /// assert!(Time::from_hms(1, 2, 3).is_ok());
189 /// ```
190 ///
191 /// ```rust
192 /// # use time::Time;
193 /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
194 /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
195 /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
196 /// ```
197 pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
198 Ok(Self::from_hms_nanos_ranged(
199 ensure_ranged!(Hours: hour),
200 ensure_ranged!(Minutes: minute),
201 ensure_ranged!(Seconds: second),
202 Nanoseconds::MIN,
203 ))
204 }
205
206 /// Create a `Time` from the hour, minute, second, and nanosecond.
207 pub(crate) const fn from_hms_nanos_ranged(
208 hour: Hours,
209 minute: Minutes,
210 second: Seconds,
211 nanosecond: Nanoseconds,
212 ) -> Self {
213 Self {
214 hour,
215 minute,
216 second,
217 nanosecond,
218 padding: Padding::Optimize,
219 }
220 }
221
222 /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
223 ///
224 /// ```rust
225 /// # use time::Time;
226 /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
227 /// ```
228 ///
229 /// ```rust
230 /// # use time::Time;
231 /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
232 /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
233 /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
234 /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
235 /// ```
236 pub const fn from_hms_milli(
237 hour: u8,
238 minute: u8,
239 second: u8,
240 millisecond: u16,
241 ) -> Result<Self, error::ComponentRange> {
242 Ok(Self::from_hms_nanos_ranged(
243 ensure_ranged!(Hours: hour),
244 ensure_ranged!(Minutes: minute),
245 ensure_ranged!(Seconds: second),
246 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)),
247 ))
248 }
249
250 /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
251 ///
252 /// ```rust
253 /// # use time::Time;
254 /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
255 /// ```
256 ///
257 /// ```rust
258 /// # use time::Time;
259 /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
260 /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
261 /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
262 /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
263 /// ```
264 pub const fn from_hms_micro(
265 hour: u8,
266 minute: u8,
267 second: u8,
268 microsecond: u32,
269 ) -> Result<Self, error::ComponentRange> {
270 Ok(Self::from_hms_nanos_ranged(
271 ensure_ranged!(Hours: hour),
272 ensure_ranged!(Minutes: minute),
273 ensure_ranged!(Seconds: second),
274 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)),
275 ))
276 }
277
278 /// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
279 ///
280 /// ```rust
281 /// # use time::Time;
282 /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
283 /// ```
284 ///
285 /// ```rust
286 /// # use time::Time;
287 /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
288 /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
289 /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
290 /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
291 /// ```
292 pub const fn from_hms_nano(
293 hour: u8,
294 minute: u8,
295 second: u8,
296 nanosecond: u32,
297 ) -> Result<Self, error::ComponentRange> {
298 Ok(Self::from_hms_nanos_ranged(
299 ensure_ranged!(Hours: hour),
300 ensure_ranged!(Minutes: minute),
301 ensure_ranged!(Seconds: second),
302 ensure_ranged!(Nanoseconds: nanosecond),
303 ))
304 }
305
306 /// Get the clock hour, minute, and second.
307 ///
308 /// ```rust
309 /// # use time_macros::time;
310 /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
311 /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
312 /// ```
313 pub const fn as_hms(self) -> (u8, u8, u8) {
314 (self.hour.get(), self.minute.get(), self.second.get())
315 }
316
317 /// Get the clock hour, minute, second, and millisecond.
318 ///
319 /// ```rust
320 /// # use time_macros::time;
321 /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
322 /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
323 /// ```
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 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
344 (
345 self.hour.get(),
346 self.minute.get(),
347 self.second.get(),
348 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
349 )
350 }
351
352 /// Get the clock hour, minute, second, and nanosecond.
353 ///
354 /// ```rust
355 /// # use time_macros::time;
356 /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
357 /// assert_eq!(
358 /// time!(23:59:59.999_999_999).as_hms_nano(),
359 /// (23, 59, 59, 999_999_999)
360 /// );
361 /// ```
362 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
363 (
364 self.hour.get(),
365 self.minute.get(),
366 self.second.get(),
367 self.nanosecond.get(),
368 )
369 }
370
371 /// Get the clock hour, minute, second, and nanosecond.
372 #[cfg(feature = "quickcheck")]
373 pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
374 (self.hour, self.minute, self.second, self.nanosecond)
375 }
376
377 /// Get the clock hour.
378 ///
379 /// The returned value will always be in the range `0..24`.
380 ///
381 /// ```rust
382 /// # use time_macros::time;
383 /// assert_eq!(time!(0:00:00).hour(), 0);
384 /// assert_eq!(time!(23:59:59).hour(), 23);
385 /// ```
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 pub const fn minute(self) -> u8 {
400 self.minute.get()
401 }
402
403 /// Get the second within the minute.
404 ///
405 /// The returned value will always be in the range `0..60`.
406 ///
407 /// ```rust
408 /// # use time_macros::time;
409 /// assert_eq!(time!(0:00:00).second(), 0);
410 /// assert_eq!(time!(23:59:59).second(), 59);
411 /// ```
412 pub const fn second(self) -> u8 {
413 self.second.get()
414 }
415
416 /// Get the milliseconds within the second.
417 ///
418 /// The returned value will always be in the range `0..1_000`.
419 ///
420 /// ```rust
421 /// # use time_macros::time;
422 /// assert_eq!(time!(0:00).millisecond(), 0);
423 /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
424 /// ```
425 pub const fn millisecond(self) -> u16 {
426 (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
427 }
428
429 /// Get the microseconds within the second.
430 ///
431 /// The returned value will always be in the range `0..1_000_000`.
432 ///
433 /// ```rust
434 /// # use time_macros::time;
435 /// assert_eq!(time!(0:00).microsecond(), 0);
436 /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
437 /// ```
438 pub const fn microsecond(self) -> u32 {
439 self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
440 }
441
442 /// Get the nanoseconds within the second.
443 ///
444 /// The returned value will always be in the range `0..1_000_000_000`.
445 ///
446 /// ```rust
447 /// # use time_macros::time;
448 /// assert_eq!(time!(0:00).nanosecond(), 0);
449 /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
450 /// ```
451 pub const fn nanosecond(self) -> u32 {
452 self.nanosecond.get()
453 }
454
455 /// Determine the [`Duration`] that, if added to `self`, would result in the parameter.
456 ///
457 /// ```rust
458 /// # use time::Time;
459 /// # use time::ext::NumericalDuration;
460 /// # use time_macros::time;
461 /// assert_eq!(time!(18:00).duration_until(Time::MIDNIGHT), 6.hours());
462 /// assert_eq!(time!(23:00).duration_until(time!(1:00)), 2.hours());
463 /// ```
464 pub const fn duration_until(self, other: Self) -> Duration {
465 let mut nanoseconds = other.nanosecond.get() as i32 - self.nanosecond.get() as i32;
466 let mut seconds = other.second.get() as i8 - self.second.get() as i8;
467 let mut minutes = other.minute.get() as i8 - self.minute.get() as i8;
468 let mut hours = other.hour.get() as i8 - self.hour.get() as i8;
469
470 // Safety: For all four variables, the bounds are obviously true given the previous bounds
471 // and nature of subtraction.
472 unsafe {
473 hint::assert_unchecked(
474 nanoseconds >= Nanoseconds::MIN.get() as i32 - Nanoseconds::MAX.get() as i32,
475 );
476 hint::assert_unchecked(
477 nanoseconds <= Nanoseconds::MAX.get() as i32 - Nanoseconds::MIN.get() as i32,
478 );
479 hint::assert_unchecked(seconds >= Seconds::MIN.get() as i8 - Seconds::MAX.get() as i8);
480 hint::assert_unchecked(seconds <= Seconds::MAX.get() as i8 - Seconds::MIN.get() as i8);
481 hint::assert_unchecked(minutes >= Minutes::MIN.get() as i8 - Minutes::MAX.get() as i8);
482 hint::assert_unchecked(minutes <= Minutes::MAX.get() as i8 - Minutes::MIN.get() as i8);
483 hint::assert_unchecked(hours >= Hours::MIN.get() as i8 - Hours::MAX.get() as i8);
484 hint::assert_unchecked(hours <= Hours::MAX.get() as i8 - Hours::MIN.get() as i8);
485 }
486
487 if self.as_u64() > other.as_u64() {
488 hours += Hour::per_t::<i8>(Day);
489 }
490
491 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
492 cascade!(seconds in 0..Second::per_t(Minute) => minutes);
493 cascade!(minutes in 0..Minute::per_t(Hour) => hours);
494
495 // Safety: The range of `nanoseconds` is guaranteed by the cascades above.
496 unsafe {
497 Duration::new_unchecked(
498 hours as i64 * Second::per_t::<i64>(Hour)
499 + minutes as i64 * Second::per_t::<i64>(Minute)
500 + seconds as i64,
501 nanoseconds,
502 )
503 }
504 }
505
506 /// Determine the [`Duration`] that, if added to the parameter, would result in `self`.
507 ///
508 /// ```rust
509 /// # use time::Time;
510 /// # use time::ext::NumericalDuration;
511 /// # use time_macros::time;
512 /// assert_eq!(Time::MIDNIGHT.duration_since(time!(18:00)), 6.hours());
513 /// assert_eq!(time!(1:00).duration_since(time!(23:00)), 2.hours());
514 /// ```
515 pub const fn duration_since(self, other: Self) -> Duration {
516 other.duration_until(self)
517 }
518
519 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
520 /// the date is different.
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 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
532 cascade!(seconds in 0..Second::per_t(Minute) => minutes);
533 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 // Safety: The cascades above ensure the values are in range.
545 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 /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
557 /// whether the date is different.
558 pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
559 let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
560 let mut seconds = self.second.get() as i8
561 - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
562 let mut minutes =
563 self.minute.get() as i8 - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
564 let mut hours =
565 self.hour.get() as i8 - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
566 let mut date_adjustment = DateAdjustment::None;
567
568 cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
569 cascade!(seconds in 0..Second::per_t(Minute) => minutes);
570 cascade!(minutes in 0..Minute::per_t(Hour) => hours);
571 if hours >= Hour::per_t(Day) {
572 hours -= Hour::per_t::<i8>(Day);
573 date_adjustment = DateAdjustment::Next;
574 } else if hours < 0 {
575 hours += Hour::per_t::<i8>(Day);
576 date_adjustment = DateAdjustment::Previous;
577 }
578
579 (
580 date_adjustment,
581 // Safety: The cascades above ensure the values are in range.
582 unsafe {
583 Self::__from_hms_nanos_unchecked(
584 hours as u8,
585 minutes as u8,
586 seconds as u8,
587 nanoseconds as u32,
588 )
589 },
590 )
591 }
592
593 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
594 /// returning whether the date is the previous date as the first element of the tuple.
595 pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
596 let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
597 let mut second =
598 self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
599 let mut minute = self.minute.get()
600 + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
601 as u8;
602 let mut hour = self.hour.get()
603 + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
604 let mut is_next_day = false;
605
606 cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
607 cascade!(second in 0..Second::per_t(Minute) => minute);
608 cascade!(minute in 0..Minute::per_t(Hour) => hour);
609 if hour >= Hour::per_t::<u8>(Day) {
610 hour -= Hour::per_t::<u8>(Day);
611 is_next_day = true;
612 }
613
614 (
615 is_next_day,
616 // Safety: The cascades above ensure the values are in range.
617 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
618 )
619 }
620
621 /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
622 /// returning whether the date is the previous date as the first element of the tuple.
623 pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
624 let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
625 let mut second =
626 self.second.get() as i8 - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
627 let mut minute = self.minute.get() as i8
628 - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
629 as i8;
630 let mut hour = self.hour.get() as i8
631 - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
632 let mut is_previous_day = false;
633
634 cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
635 cascade!(second in 0..Second::per_t(Minute) => minute);
636 cascade!(minute in 0..Minute::per_t(Hour) => hour);
637 if hour < 0 {
638 hour += Hour::per_t::<i8>(Day);
639 is_previous_day = true;
640 }
641
642 (
643 is_previous_day,
644 // Safety: The cascades above ensure the values are in range.
645 unsafe {
646 Self::__from_hms_nanos_unchecked(
647 hour as u8,
648 minute as u8,
649 second as u8,
650 nanosecond as u32,
651 )
652 },
653 )
654 }
655
656 /// Replace the clock hour.
657 ///
658 /// ```rust
659 /// # use time_macros::time;
660 /// assert_eq!(
661 /// time!(01:02:03.004_005_006).replace_hour(7),
662 /// Ok(time!(07:02:03.004_005_006))
663 /// );
664 /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
665 /// ```
666 #[must_use = "This method does not mutate the original `Time`."]
667 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
668 self.hour = ensure_ranged!(Hours: hour);
669 Ok(self)
670 }
671
672 /// Replace the minutes within the hour.
673 ///
674 /// ```rust
675 /// # use time_macros::time;
676 /// assert_eq!(
677 /// time!(01:02:03.004_005_006).replace_minute(7),
678 /// Ok(time!(01:07:03.004_005_006))
679 /// );
680 /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
681 /// ```
682 #[must_use = "This method does not mutate the original `Time`."]
683 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
684 self.minute = ensure_ranged!(Minutes: minute);
685 Ok(self)
686 }
687
688 /// Replace the seconds within the minute.
689 ///
690 /// ```rust
691 /// # use time_macros::time;
692 /// assert_eq!(
693 /// time!(01:02:03.004_005_006).replace_second(7),
694 /// Ok(time!(01:02:07.004_005_006))
695 /// );
696 /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
697 /// ```
698 #[must_use = "This method does not mutate the original `Time`."]
699 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
700 self.second = ensure_ranged!(Seconds: second);
701 Ok(self)
702 }
703
704 /// Replace the milliseconds within the second.
705 ///
706 /// ```rust
707 /// # use time_macros::time;
708 /// assert_eq!(
709 /// time!(01:02:03.004_005_006).replace_millisecond(7),
710 /// Ok(time!(01:02:03.007))
711 /// );
712 /// assert!(time!(01:02:03.004_005_006)
713 /// .replace_millisecond(1_000)
714 /// .is_err()); // 1_000 isn't a valid millisecond
715 /// ```
716 #[must_use = "This method does not mutate the original `Time`."]
717 pub const fn replace_millisecond(
718 mut self,
719 millisecond: u16,
720 ) -> Result<Self, error::ComponentRange> {
721 self.nanosecond =
722 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
723 Ok(self)
724 }
725
726 /// Replace the microseconds within the second.
727 ///
728 /// ```rust
729 /// # use time_macros::time;
730 /// assert_eq!(
731 /// time!(01:02:03.004_005_006).replace_microsecond(7_008),
732 /// Ok(time!(01:02:03.007_008))
733 /// );
734 /// assert!(time!(01:02:03.004_005_006)
735 /// .replace_microsecond(1_000_000)
736 /// .is_err()); // 1_000_000 isn't a valid microsecond
737 /// ```
738 #[must_use = "This method does not mutate the original `Time`."]
739 pub const fn replace_microsecond(
740 mut self,
741 microsecond: u32,
742 ) -> Result<Self, error::ComponentRange> {
743 self.nanosecond =
744 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
745 Ok(self)
746 }
747
748 /// Replace the nanoseconds within the second.
749 ///
750 /// ```rust
751 /// # use time_macros::time;
752 /// assert_eq!(
753 /// time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
754 /// Ok(time!(01:02:03.007_008_009))
755 /// );
756 /// assert!(time!(01:02:03.004_005_006)
757 /// .replace_nanosecond(1_000_000_000)
758 /// .is_err()); // 1_000_000_000 isn't a valid nanosecond
759 /// ```
760 #[must_use = "This method does not mutate the original `Time`."]
761 pub const fn replace_nanosecond(
762 mut self,
763 nanosecond: u32,
764 ) -> Result<Self, error::ComponentRange> {
765 self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
766 Ok(self)
767 }
768}
769
770#[cfg(feature = "formatting")]
771impl Time {
772 /// Format the `Time` using the provided [format description](crate::format_description).
773 pub fn format_into(
774 self,
775 output: &mut (impl io::Write + ?Sized),
776 format: &(impl Formattable + ?Sized),
777 ) -> Result<usize, error::Format> {
778 format.format_into(output, None, Some(self), None)
779 }
780
781 /// Format the `Time` using the provided [format description](crate::format_description).
782 ///
783 /// ```rust
784 /// # use time::format_description;
785 /// # use time_macros::time;
786 /// let format = format_description::parse("[hour]:[minute]:[second]")?;
787 /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
788 /// # Ok::<_, time::Error>(())
789 /// ```
790 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
791 format.format(None, Some(self), None)
792 }
793}
794
795#[cfg(feature = "parsing")]
796impl Time {
797 /// Parse a `Time` from the input using the provided [format
798 /// description](crate::format_description).
799 ///
800 /// ```rust
801 /// # use time::Time;
802 /// # use time_macros::{time, format_description};
803 /// let format = format_description!("[hour]:[minute]:[second]");
804 /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
805 /// # Ok::<_, time::Error>(())
806 /// ```
807 pub fn parse(
808 input: &str,
809 description: &(impl Parsable + ?Sized),
810 ) -> Result<Self, error::Parse> {
811 description.parse_time(input.as_bytes())
812 }
813}
814
815mod private {
816 #[non_exhaustive]
817 #[derive(Debug, Clone, Copy)]
818 pub struct TimeMetadata {
819 /// How many characters wide the formatted subsecond is.
820 pub(super) subsecond_width: u8,
821 /// The value to use when formatting the subsecond. Leading zeroes will be added as
822 /// necessary.
823 pub(super) subsecond_value: u32,
824 }
825}
826use private::TimeMetadata;
827
828impl SmartDisplay for Time {
829 type Metadata = TimeMetadata;
830
831 fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
832 let (subsecond_value, subsecond_width) = match self.nanosecond() {
833 nanos if nanos % 10 != 0 => (nanos, 9),
834 nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
835 nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
836 nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
837 nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
838 nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
839 nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
840 nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
841 nanos => (nanos / 100_000_000, 1),
842 };
843
844 let formatted_width = smart_display::padded_width_of!(
845 self.hour.get(),
846 ":",
847 self.minute.get() => width(2) fill('0'),
848 ":",
849 self.second.get() => width(2) fill('0'),
850 ".",
851 ) + subsecond_width;
852
853 Metadata::new(
854 formatted_width,
855 self,
856 TimeMetadata {
857 subsecond_width: subsecond_width.truncate(),
858 subsecond_value,
859 },
860 )
861 }
862
863 fn fmt_with_metadata(
864 &self,
865 f: &mut fmt::Formatter<'_>,
866 metadata: Metadata<Self>,
867 ) -> fmt::Result {
868 let subsecond_width = metadata.subsecond_width.extend();
869 let subsecond_value = metadata.subsecond_value;
870
871 f.pad_with_width(
872 metadata.unpadded_width(),
873 format_args!(
874 "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
875 self.hour, self.minute, self.second
876 ),
877 )
878 }
879}
880
881impl fmt::Display for Time {
882 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
883 SmartDisplay::fmt(self, f)
884 }
885}
886
887impl fmt::Debug for Time {
888 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
889 fmt::Display::fmt(self, f)
890 }
891}
892
893impl Add<Duration> for Time {
894 type Output = Self;
895
896 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
897 ///
898 /// ```rust
899 /// # use time::ext::NumericalDuration;
900 /// # use time_macros::time;
901 /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
902 /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
903 /// ```
904 fn add(self, duration: Duration) -> Self::Output {
905 self.adjusting_add(duration).1
906 }
907}
908
909impl Add<StdDuration> for Time {
910 type Output = Self;
911
912 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
913 ///
914 /// ```rust
915 /// # use time::ext::NumericalStdDuration;
916 /// # use time_macros::time;
917 /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
918 /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
919 /// ```
920 fn add(self, duration: StdDuration) -> Self::Output {
921 self.adjusting_add_std(duration).1
922 }
923}
924
925impl_add_assign!(Time: Duration, StdDuration);
926
927impl Sub<Duration> for Time {
928 type Output = Self;
929
930 /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
931 ///
932 /// ```rust
933 /// # use time::ext::NumericalDuration;
934 /// # use time_macros::time;
935 /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
936 /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
937 /// ```
938 fn sub(self, duration: Duration) -> Self::Output {
939 self.adjusting_sub(duration).1
940 }
941}
942
943impl Sub<StdDuration> for Time {
944 type Output = Self;
945
946 /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
947 ///
948 /// ```rust
949 /// # use time::ext::NumericalStdDuration;
950 /// # use time_macros::time;
951 /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
952 /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
953 /// ```
954 fn sub(self, duration: StdDuration) -> Self::Output {
955 self.adjusting_sub_std(duration).1
956 }
957}
958
959impl_sub_assign!(Time: Duration, StdDuration);
960
961impl Sub for Time {
962 type Output = Duration;
963
964 /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
965 /// the same calendar day.
966 ///
967 /// ```rust
968 /// # use time::ext::NumericalDuration;
969 /// # use time_macros::time;
970 /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
971 /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
972 /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
973 /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
974 /// ```
975 fn sub(self, rhs: Self) -> Self::Output {
976 let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
977 let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
978 let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
979 let nanosecond_diff =
980 self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
981
982 let seconds = hour_diff.extend::<i64>() * Second::per_t::<i64>(Hour)
983 + minute_diff.extend::<i64>() * Second::per_t::<i64>(Minute)
984 + second_diff.extend::<i64>();
985
986 let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
987 (
988 seconds - 1,
989 nanosecond_diff + Nanosecond::per_t::<i32>(Second),
990 )
991 } else if seconds < 0 && nanosecond_diff > 0 {
992 (
993 seconds + 1,
994 nanosecond_diff - Nanosecond::per_t::<i32>(Second),
995 )
996 } else {
997 (seconds, nanosecond_diff)
998 };
999
1000 // Safety: `nanoseconds` is in range due to the overflow handling.
1001 unsafe { Duration::new_unchecked(seconds, nanoseconds) }
1002 }
1003}