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