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, 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(Day) - 1 }>;
36/// The type of the `minute` field of `Time`.
37type Minutes = RangedU8<0, { Minute::per(Hour) - 1 }>;
38/// The type of the `second` field of `Time`.
39type Seconds = RangedU8<0, { Second::per(Minute) - 1 }>;
40/// The type of the `nanosecond` field of `Time`.
41type Nanoseconds = RangedU32<0, { Nanosecond::per(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(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(Microsecond) as u32),
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(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(Microsecond) as u32,
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(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(Microsecond) as u32
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 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
456 /// the date is different.
457 pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
458 let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds();
459 let mut seconds =
460 self.second.get() as i8 + (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
461 let mut minutes =
462 self.minute.get() as i8 + (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
463 let mut hours =
464 self.hour.get() as i8 + (duration.whole_hours() % Hour::per(Day) as i64) as i8;
465 let mut date_adjustment = DateAdjustment::None;
466
467 cascade!(nanoseconds in 0..Nanosecond::per(Second) as i32 => seconds);
468 cascade!(seconds in 0..Second::per(Minute) as i8 => minutes);
469 cascade!(minutes in 0..Minute::per(Hour) as i8 => hours);
470 if hours >= Hour::per(Day) as i8 {
471 hours -= Hour::per(Day) as i8;
472 date_adjustment = DateAdjustment::Next;
473 } else if hours < 0 {
474 hours += Hour::per(Day) as i8;
475 date_adjustment = DateAdjustment::Previous;
476 }
477
478 (
479 date_adjustment,
480 // Safety: The cascades above ensure the values are in range.
481 unsafe {
482 Self::__from_hms_nanos_unchecked(
483 hours as u8,
484 minutes as u8,
485 seconds as u8,
486 nanoseconds as u32,
487 )
488 },
489 )
490 }
491
492 /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
493 /// whether the date is different.
494 pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
495 let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
496 let mut seconds =
497 self.second.get() as i8 - (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
498 let mut minutes =
499 self.minute.get() as i8 - (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
500 let mut hours =
501 self.hour.get() as i8 - (duration.whole_hours() % Hour::per(Day) as i64) as i8;
502 let mut date_adjustment = DateAdjustment::None;
503
504 cascade!(nanoseconds in 0..Nanosecond::per(Second) as i32 => seconds);
505 cascade!(seconds in 0..Second::per(Minute) as i8 => minutes);
506 cascade!(minutes in 0..Minute::per(Hour) as i8 => hours);
507 if hours >= Hour::per(Day) as i8 {
508 hours -= Hour::per(Day) as i8;
509 date_adjustment = DateAdjustment::Next;
510 } else if hours < 0 {
511 hours += Hour::per(Day) as i8;
512 date_adjustment = DateAdjustment::Previous;
513 }
514
515 (
516 date_adjustment,
517 // Safety: The cascades above ensure the values are in range.
518 unsafe {
519 Self::__from_hms_nanos_unchecked(
520 hours as u8,
521 minutes as u8,
522 seconds as u8,
523 nanoseconds as u32,
524 )
525 },
526 )
527 }
528
529 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
530 /// returning whether the date is the previous date as the first element of the tuple.
531 pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
532 let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
533 let mut second =
534 self.second.get() + (duration.as_secs() % Second::per(Minute) as u64) as u8;
535 let mut minute = self.minute.get()
536 + ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as u8;
537 let mut hour = self.hour.get()
538 + ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as u8;
539 let mut is_next_day = false;
540
541 cascade!(nanosecond in 0..Nanosecond::per(Second) => second);
542 cascade!(second in 0..Second::per(Minute) => minute);
543 cascade!(minute in 0..Minute::per(Hour) => hour);
544 if hour >= Hour::per(Day) {
545 hour -= Hour::per(Day);
546 is_next_day = true;
547 }
548
549 (
550 is_next_day,
551 // Safety: The cascades above ensure the values are in range.
552 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
553 )
554 }
555
556 /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
557 /// returning whether the date is the previous date as the first element of the tuple.
558 pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
559 let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
560 let mut second =
561 self.second.get() as i8 - (duration.as_secs() % Second::per(Minute) as u64) as i8;
562 let mut minute = self.minute.get() as i8
563 - ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as i8;
564 let mut hour = self.hour.get() as i8
565 - ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as i8;
566 let mut is_previous_day = false;
567
568 cascade!(nanosecond in 0..Nanosecond::per(Second) as i32 => second);
569 cascade!(second in 0..Second::per(Minute) as i8 => minute);
570 cascade!(minute in 0..Minute::per(Hour) as i8 => hour);
571 if hour < 0 {
572 hour += Hour::per(Day) as i8;
573 is_previous_day = true;
574 }
575
576 (
577 is_previous_day,
578 // Safety: The cascades above ensure the values are in range.
579 unsafe {
580 Self::__from_hms_nanos_unchecked(
581 hour as u8,
582 minute as u8,
583 second as u8,
584 nanosecond as u32,
585 )
586 },
587 )
588 }
589
590 /// Replace the clock hour.
591 ///
592 /// ```rust
593 /// # use time_macros::time;
594 /// assert_eq!(
595 /// time!(01:02:03.004_005_006).replace_hour(7),
596 /// Ok(time!(07:02:03.004_005_006))
597 /// );
598 /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
599 /// ```
600 #[must_use = "This method does not mutate the original `Time`."]
601 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
602 self.hour = ensure_ranged!(Hours: hour);
603 Ok(self)
604 }
605
606 /// Replace the minutes within the hour.
607 ///
608 /// ```rust
609 /// # use time_macros::time;
610 /// assert_eq!(
611 /// time!(01:02:03.004_005_006).replace_minute(7),
612 /// Ok(time!(01:07:03.004_005_006))
613 /// );
614 /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
615 /// ```
616 #[must_use = "This method does not mutate the original `Time`."]
617 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
618 self.minute = ensure_ranged!(Minutes: minute);
619 Ok(self)
620 }
621
622 /// Replace the seconds within the minute.
623 ///
624 /// ```rust
625 /// # use time_macros::time;
626 /// assert_eq!(
627 /// time!(01:02:03.004_005_006).replace_second(7),
628 /// Ok(time!(01:02:07.004_005_006))
629 /// );
630 /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
631 /// ```
632 #[must_use = "This method does not mutate the original `Time`."]
633 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
634 self.second = ensure_ranged!(Seconds: second);
635 Ok(self)
636 }
637
638 /// Replace the milliseconds within the second.
639 ///
640 /// ```rust
641 /// # use time_macros::time;
642 /// assert_eq!(
643 /// time!(01:02:03.004_005_006).replace_millisecond(7),
644 /// Ok(time!(01:02:03.007))
645 /// );
646 /// assert!(time!(01:02:03.004_005_006)
647 /// .replace_millisecond(1_000)
648 /// .is_err()); // 1_000 isn't a valid millisecond
649 /// ```
650 #[must_use = "This method does not mutate the original `Time`."]
651 pub const fn replace_millisecond(
652 mut self,
653 millisecond: u16,
654 ) -> Result<Self, error::ComponentRange> {
655 self.nanosecond =
656 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond));
657 Ok(self)
658 }
659
660 /// Replace the microseconds within the second.
661 ///
662 /// ```rust
663 /// # use time_macros::time;
664 /// assert_eq!(
665 /// time!(01:02:03.004_005_006).replace_microsecond(7_008),
666 /// Ok(time!(01:02:03.007_008))
667 /// );
668 /// assert!(time!(01:02:03.004_005_006)
669 /// .replace_microsecond(1_000_000)
670 /// .is_err()); // 1_000_000 isn't a valid microsecond
671 /// ```
672 #[must_use = "This method does not mutate the original `Time`."]
673 pub const fn replace_microsecond(
674 mut self,
675 microsecond: u32,
676 ) -> Result<Self, error::ComponentRange> {
677 self.nanosecond =
678 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32);
679 Ok(self)
680 }
681
682 /// Replace the nanoseconds within the second.
683 ///
684 /// ```rust
685 /// # use time_macros::time;
686 /// assert_eq!(
687 /// time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
688 /// Ok(time!(01:02:03.007_008_009))
689 /// );
690 /// assert!(time!(01:02:03.004_005_006)
691 /// .replace_nanosecond(1_000_000_000)
692 /// .is_err()); // 1_000_000_000 isn't a valid nanosecond
693 /// ```
694 #[must_use = "This method does not mutate the original `Time`."]
695 pub const fn replace_nanosecond(
696 mut self,
697 nanosecond: u32,
698 ) -> Result<Self, error::ComponentRange> {
699 self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
700 Ok(self)
701 }
702}
703
704#[cfg(feature = "formatting")]
705impl Time {
706 /// Format the `Time` using the provided [format description](crate::format_description).
707 pub fn format_into(
708 self,
709 output: &mut (impl io::Write + ?Sized),
710 format: &(impl Formattable + ?Sized),
711 ) -> Result<usize, error::Format> {
712 format.format_into(output, None, Some(self), None)
713 }
714
715 /// Format the `Time` using the provided [format description](crate::format_description).
716 ///
717 /// ```rust
718 /// # use time::format_description;
719 /// # use time_macros::time;
720 /// let format = format_description::parse("[hour]:[minute]:[second]")?;
721 /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
722 /// # Ok::<_, time::Error>(())
723 /// ```
724 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
725 format.format(None, Some(self), None)
726 }
727}
728
729#[cfg(feature = "parsing")]
730impl Time {
731 /// Parse a `Time` from the input using the provided [format
732 /// description](crate::format_description).
733 ///
734 /// ```rust
735 /// # use time::Time;
736 /// # use time_macros::{time, format_description};
737 /// let format = format_description!("[hour]:[minute]:[second]");
738 /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
739 /// # Ok::<_, time::Error>(())
740 /// ```
741 pub fn parse(
742 input: &str,
743 description: &(impl Parsable + ?Sized),
744 ) -> Result<Self, error::Parse> {
745 description.parse_time(input.as_bytes())
746 }
747}
748
749mod private {
750 #[non_exhaustive]
751 #[derive(Debug, Clone, Copy)]
752 pub struct TimeMetadata {
753 /// How many characters wide the formatted subsecond is.
754 pub(super) subsecond_width: u8,
755 /// The value to use when formatting the subsecond. Leading zeroes will be added as
756 /// necessary.
757 pub(super) subsecond_value: u32,
758 }
759}
760use private::TimeMetadata;
761
762impl SmartDisplay for Time {
763 type Metadata = TimeMetadata;
764
765 fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
766 let (subsecond_value, subsecond_width) = match self.nanosecond() {
767 nanos if nanos % 10 != 0 => (nanos, 9),
768 nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
769 nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
770 nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
771 nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
772 nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
773 nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
774 nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
775 nanos => (nanos / 100_000_000, 1),
776 };
777
778 let formatted_width = smart_display::padded_width_of!(
779 self.hour.get(),
780 ":",
781 self.minute.get() => width(2) fill('0'),
782 ":",
783 self.second.get() => width(2) fill('0'),
784 ".",
785 ) + subsecond_width;
786
787 Metadata::new(
788 formatted_width,
789 self,
790 TimeMetadata {
791 subsecond_width: subsecond_width.truncate(),
792 subsecond_value,
793 },
794 )
795 }
796
797 fn fmt_with_metadata(
798 &self,
799 f: &mut fmt::Formatter<'_>,
800 metadata: Metadata<Self>,
801 ) -> fmt::Result {
802 let subsecond_width = metadata.subsecond_width.extend();
803 let subsecond_value = metadata.subsecond_value;
804
805 f.pad_with_width(
806 metadata.unpadded_width(),
807 format_args!(
808 "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
809 self.hour, self.minute, self.second
810 ),
811 )
812 }
813}
814
815impl fmt::Display for Time {
816 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
817 SmartDisplay::fmt(self, f)
818 }
819}
820
821impl fmt::Debug for Time {
822 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
823 fmt::Display::fmt(self, f)
824 }
825}
826
827impl Add<Duration> for Time {
828 type Output = Self;
829
830 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
831 ///
832 /// ```rust
833 /// # use time::ext::NumericalDuration;
834 /// # use time_macros::time;
835 /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
836 /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
837 /// ```
838 fn add(self, duration: Duration) -> Self::Output {
839 self.adjusting_add(duration).1
840 }
841}
842
843impl Add<StdDuration> for Time {
844 type Output = Self;
845
846 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
847 ///
848 /// ```rust
849 /// # use time::ext::NumericalStdDuration;
850 /// # use time_macros::time;
851 /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
852 /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
853 /// ```
854 fn add(self, duration: StdDuration) -> Self::Output {
855 self.adjusting_add_std(duration).1
856 }
857}
858
859impl_add_assign!(Time: Duration, StdDuration);
860
861impl Sub<Duration> for Time {
862 type Output = Self;
863
864 /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
865 ///
866 /// ```rust
867 /// # use time::ext::NumericalDuration;
868 /// # use time_macros::time;
869 /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
870 /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
871 /// ```
872 fn sub(self, duration: Duration) -> Self::Output {
873 self.adjusting_sub(duration).1
874 }
875}
876
877impl Sub<StdDuration> for Time {
878 type Output = Self;
879
880 /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
881 ///
882 /// ```rust
883 /// # use time::ext::NumericalStdDuration;
884 /// # use time_macros::time;
885 /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
886 /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
887 /// ```
888 fn sub(self, duration: StdDuration) -> Self::Output {
889 self.adjusting_sub_std(duration).1
890 }
891}
892
893impl_sub_assign!(Time: Duration, StdDuration);
894
895impl Sub for Time {
896 type Output = Duration;
897
898 /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
899 /// the same calendar day.
900 ///
901 /// ```rust
902 /// # use time::ext::NumericalDuration;
903 /// # use time_macros::time;
904 /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
905 /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
906 /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
907 /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
908 /// ```
909 fn sub(self, rhs: Self) -> Self::Output {
910 let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
911 let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
912 let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
913 let nanosecond_diff =
914 self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
915
916 let seconds = hour_diff.extend::<i64>() * Second::per(Hour).cast_signed().extend::<i64>()
917 + minute_diff.extend::<i64>() * Second::per(Minute).cast_signed().extend::<i64>()
918 + second_diff.extend::<i64>();
919
920 let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
921 (
922 seconds - 1,
923 nanosecond_diff + Nanosecond::per(Second).cast_signed(),
924 )
925 } else if seconds < 0 && nanosecond_diff > 0 {
926 (
927 seconds + 1,
928 nanosecond_diff - Nanosecond::per(Second).cast_signed(),
929 )
930 } else {
931 (seconds, nanosecond_diff)
932 };
933
934 // Safety: `nanoseconds` is in range due to the overflow handling.
935 unsafe { Duration::new_unchecked(seconds, nanoseconds) }
936 }
937}