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