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 // region: constructors
159 /// Create a `Time` from its components.
160 ///
161 /// # Safety
162 ///
163 /// - `hours` must be in the range `0..=23`.
164 /// - `minutes` must be in the range `0..=59`.
165 /// - `seconds` must be in the range `0..=59`.
166 /// - `nanoseconds` must be in the range `0..=999_999_999`.
167 #[doc(hidden)]
168 pub const unsafe fn __from_hms_nanos_unchecked(
169 hour: u8,
170 minute: u8,
171 second: u8,
172 nanosecond: u32,
173 ) -> Self {
174 // Safety: The caller must uphold the safety invariants.
175 unsafe {
176 Self::from_hms_nanos_ranged(
177 Hours::new_unchecked(hour),
178 Minutes::new_unchecked(minute),
179 Seconds::new_unchecked(second),
180 Nanoseconds::new_unchecked(nanosecond),
181 )
182 }
183 }
184
185 /// Attempt to create a `Time` from the hour, minute, and second.
186 ///
187 /// ```rust
188 /// # use time::Time;
189 /// assert!(Time::from_hms(1, 2, 3).is_ok());
190 /// ```
191 ///
192 /// ```rust
193 /// # use time::Time;
194 /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
195 /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
196 /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
197 /// ```
198 pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
199 Ok(Self::from_hms_nanos_ranged(
200 ensure_ranged!(Hours: hour),
201 ensure_ranged!(Minutes: minute),
202 ensure_ranged!(Seconds: second),
203 Nanoseconds::MIN,
204 ))
205 }
206
207 /// Create a `Time` from the hour, minute, second, and nanosecond.
208 pub(crate) const fn from_hms_nanos_ranged(
209 hour: Hours,
210 minute: Minutes,
211 second: Seconds,
212 nanosecond: Nanoseconds,
213 ) -> Self {
214 Self {
215 hour,
216 minute,
217 second,
218 nanosecond,
219 padding: Padding::Optimize,
220 }
221 }
222
223 /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
224 ///
225 /// ```rust
226 /// # use time::Time;
227 /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
228 /// ```
229 ///
230 /// ```rust
231 /// # use time::Time;
232 /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
233 /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
234 /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
235 /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
236 /// ```
237 pub const fn from_hms_milli(
238 hour: u8,
239 minute: u8,
240 second: u8,
241 millisecond: u16,
242 ) -> Result<Self, error::ComponentRange> {
243 Ok(Self::from_hms_nanos_ranged(
244 ensure_ranged!(Hours: hour),
245 ensure_ranged!(Minutes: minute),
246 ensure_ranged!(Seconds: second),
247 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond)),
248 ))
249 }
250
251 /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
252 ///
253 /// ```rust
254 /// # use time::Time;
255 /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
256 /// ```
257 ///
258 /// ```rust
259 /// # use time::Time;
260 /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
261 /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
262 /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
263 /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
264 /// ```
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(Microsecond) as u32),
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 pub const fn from_hms_nano(
294 hour: u8,
295 minute: u8,
296 second: u8,
297 nanosecond: u32,
298 ) -> Result<Self, error::ComponentRange> {
299 Ok(Self::from_hms_nanos_ranged(
300 ensure_ranged!(Hours: hour),
301 ensure_ranged!(Minutes: minute),
302 ensure_ranged!(Seconds: second),
303 ensure_ranged!(Nanoseconds: nanosecond),
304 ))
305 }
306 // endregion constructors
307
308 // region: getters
309 /// Get the clock hour, minute, and second.
310 ///
311 /// ```rust
312 /// # use time_macros::time;
313 /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
314 /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
315 /// ```
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 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
328 (
329 self.hour.get(),
330 self.minute.get(),
331 self.second.get(),
332 (self.nanosecond.get() / Nanosecond::per(Millisecond)) as u16,
333 )
334 }
335
336 /// Get the clock hour, minute, second, and microsecond.
337 ///
338 /// ```rust
339 /// # use time_macros::time;
340 /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
341 /// assert_eq!(
342 /// time!(23:59:59.999_999).as_hms_micro(),
343 /// (23, 59, 59, 999_999)
344 /// );
345 /// ```
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(Microsecond) as u32,
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 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
366 (
367 self.hour.get(),
368 self.minute.get(),
369 self.second.get(),
370 self.nanosecond.get(),
371 )
372 }
373
374 /// Get the clock hour, minute, second, and nanosecond.
375 #[cfg(feature = "quickcheck")]
376 pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
377 (self.hour, self.minute, self.second, self.nanosecond)
378 }
379
380 /// Get the clock hour.
381 ///
382 /// The returned value will always be in the range `0..24`.
383 ///
384 /// ```rust
385 /// # use time_macros::time;
386 /// assert_eq!(time!(0:00:00).hour(), 0);
387 /// assert_eq!(time!(23:59:59).hour(), 23);
388 /// ```
389 pub const fn hour(self) -> u8 {
390 self.hour.get()
391 }
392
393 /// Get the minute within the hour.
394 ///
395 /// The returned value will always be in the range `0..60`.
396 ///
397 /// ```rust
398 /// # use time_macros::time;
399 /// assert_eq!(time!(0:00:00).minute(), 0);
400 /// assert_eq!(time!(23:59:59).minute(), 59);
401 /// ```
402 pub const fn minute(self) -> u8 {
403 self.minute.get()
404 }
405
406 /// Get the second within the minute.
407 ///
408 /// The returned value will always be in the range `0..60`.
409 ///
410 /// ```rust
411 /// # use time_macros::time;
412 /// assert_eq!(time!(0:00:00).second(), 0);
413 /// assert_eq!(time!(23:59:59).second(), 59);
414 /// ```
415 pub const fn second(self) -> u8 {
416 self.second.get()
417 }
418
419 /// Get the milliseconds within the second.
420 ///
421 /// The returned value will always be in the range `0..1_000`.
422 ///
423 /// ```rust
424 /// # use time_macros::time;
425 /// assert_eq!(time!(0:00).millisecond(), 0);
426 /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
427 /// ```
428 pub const fn millisecond(self) -> u16 {
429 (self.nanosecond.get() / Nanosecond::per(Millisecond)) as _
430 }
431
432 /// Get the microseconds within the second.
433 ///
434 /// The returned value will always be in the range `0..1_000_000`.
435 ///
436 /// ```rust
437 /// # use time_macros::time;
438 /// assert_eq!(time!(0:00).microsecond(), 0);
439 /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
440 /// ```
441 pub const fn microsecond(self) -> u32 {
442 self.nanosecond.get() / Nanosecond::per(Microsecond) as u32
443 }
444
445 /// Get the nanoseconds within the second.
446 ///
447 /// The returned value will always be in the range `0..1_000_000_000`.
448 ///
449 /// ```rust
450 /// # use time_macros::time;
451 /// assert_eq!(time!(0:00).nanosecond(), 0);
452 /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
453 /// ```
454 pub const fn nanosecond(self) -> u32 {
455 self.nanosecond.get()
456 }
457 // endregion getters
458
459 // region: arithmetic helpers
460 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
461 /// the date is different.
462 pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
463 let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds();
464 let mut seconds =
465 self.second.get() as i8 + (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
466 let mut minutes =
467 self.minute.get() as i8 + (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
468 let mut hours =
469 self.hour.get() as i8 + (duration.whole_hours() % Hour::per(Day) as i64) as i8;
470 let mut date_adjustment = DateAdjustment::None;
471
472 cascade!(nanoseconds in 0..Nanosecond::per(Second) as _ => seconds);
473 cascade!(seconds in 0..Second::per(Minute) as _ => minutes);
474 cascade!(minutes in 0..Minute::per(Hour) as _ => hours);
475 if hours >= Hour::per(Day) as _ {
476 hours -= Hour::per(Day) as i8;
477 date_adjustment = DateAdjustment::Next;
478 } else if hours < 0 {
479 hours += Hour::per(Day) as i8;
480 date_adjustment = DateAdjustment::Previous;
481 }
482
483 (
484 date_adjustment,
485 // Safety: The cascades above ensure the values are in range.
486 unsafe {
487 Self::__from_hms_nanos_unchecked(
488 hours as _,
489 minutes as _,
490 seconds as _,
491 nanoseconds as _,
492 )
493 },
494 )
495 }
496
497 /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
498 /// whether the date is different.
499 pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
500 let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
501 let mut seconds =
502 self.second.get() as i8 - (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
503 let mut minutes =
504 self.minute.get() as i8 - (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
505 let mut hours =
506 self.hour.get() as i8 - (duration.whole_hours() % Hour::per(Day) as i64) as i8;
507 let mut date_adjustment = DateAdjustment::None;
508
509 cascade!(nanoseconds in 0..Nanosecond::per(Second) as _ => seconds);
510 cascade!(seconds in 0..Second::per(Minute) as _ => minutes);
511 cascade!(minutes in 0..Minute::per(Hour) as _ => hours);
512 if hours >= Hour::per(Day) as _ {
513 hours -= Hour::per(Day) as i8;
514 date_adjustment = DateAdjustment::Next;
515 } else if hours < 0 {
516 hours += Hour::per(Day) as i8;
517 date_adjustment = DateAdjustment::Previous;
518 }
519
520 (
521 date_adjustment,
522 // Safety: The cascades above ensure the values are in range.
523 unsafe {
524 Self::__from_hms_nanos_unchecked(
525 hours as _,
526 minutes as _,
527 seconds as _,
528 nanoseconds as _,
529 )
530 },
531 )
532 }
533
534 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
535 /// returning whether the date is the previous date as the first element of the tuple.
536 pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
537 let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
538 let mut second =
539 self.second.get() + (duration.as_secs() % Second::per(Minute) as u64) as u8;
540 let mut minute = self.minute.get()
541 + ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as u8;
542 let mut hour = self.hour.get()
543 + ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as u8;
544 let mut is_next_day = false;
545
546 cascade!(nanosecond in 0..Nanosecond::per(Second) => second);
547 cascade!(second in 0..Second::per(Minute) => minute);
548 cascade!(minute in 0..Minute::per(Hour) => hour);
549 if hour >= Hour::per(Day) {
550 hour -= Hour::per(Day);
551 is_next_day = true;
552 }
553
554 (
555 is_next_day,
556 // Safety: The cascades above ensure the values are in range.
557 unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
558 )
559 }
560
561 /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
562 /// returning whether the date is the previous date as the first element of the tuple.
563 pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
564 let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
565 let mut second =
566 self.second.get() as i8 - (duration.as_secs() % Second::per(Minute) as u64) as i8;
567 let mut minute = self.minute.get() as i8
568 - ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as i8;
569 let mut hour = self.hour.get() as i8
570 - ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as i8;
571 let mut is_previous_day = false;
572
573 cascade!(nanosecond in 0..Nanosecond::per(Second) as _ => second);
574 cascade!(second in 0..Second::per(Minute) as _ => minute);
575 cascade!(minute in 0..Minute::per(Hour) as _ => hour);
576 if hour < 0 {
577 hour += Hour::per(Day) as i8;
578 is_previous_day = true;
579 }
580
581 (
582 is_previous_day,
583 // Safety: The cascades above ensure the values are in range.
584 unsafe {
585 Self::__from_hms_nanos_unchecked(
586 hour as _,
587 minute as _,
588 second as _,
589 nanosecond as _,
590 )
591 },
592 )
593 }
594 // endregion arithmetic helpers
595
596 // region: replacement
597 /// Replace the clock hour.
598 ///
599 /// ```rust
600 /// # use time_macros::time;
601 /// assert_eq!(
602 /// time!(01:02:03.004_005_006).replace_hour(7),
603 /// Ok(time!(07:02:03.004_005_006))
604 /// );
605 /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
606 /// ```
607 #[must_use = "This method does not mutate the original `Time`."]
608 pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
609 self.hour = ensure_ranged!(Hours: hour);
610 Ok(self)
611 }
612
613 /// Replace the minutes within the hour.
614 ///
615 /// ```rust
616 /// # use time_macros::time;
617 /// assert_eq!(
618 /// time!(01:02:03.004_005_006).replace_minute(7),
619 /// Ok(time!(01:07:03.004_005_006))
620 /// );
621 /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
622 /// ```
623 #[must_use = "This method does not mutate the original `Time`."]
624 pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
625 self.minute = ensure_ranged!(Minutes: minute);
626 Ok(self)
627 }
628
629 /// Replace the seconds within the minute.
630 ///
631 /// ```rust
632 /// # use time_macros::time;
633 /// assert_eq!(
634 /// time!(01:02:03.004_005_006).replace_second(7),
635 /// Ok(time!(01:02:07.004_005_006))
636 /// );
637 /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
638 /// ```
639 #[must_use = "This method does not mutate the original `Time`."]
640 pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
641 self.second = ensure_ranged!(Seconds: second);
642 Ok(self)
643 }
644
645 /// Replace the milliseconds within the second.
646 ///
647 /// ```rust
648 /// # use time_macros::time;
649 /// assert_eq!(
650 /// time!(01:02:03.004_005_006).replace_millisecond(7),
651 /// Ok(time!(01:02:03.007))
652 /// );
653 /// assert!(time!(01:02:03.004_005_006)
654 /// .replace_millisecond(1_000)
655 /// .is_err()); // 1_000 isn't a valid millisecond
656 /// ```
657 #[must_use = "This method does not mutate the original `Time`."]
658 pub const fn replace_millisecond(
659 mut self,
660 millisecond: u16,
661 ) -> Result<Self, error::ComponentRange> {
662 self.nanosecond =
663 ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond));
664 Ok(self)
665 }
666
667 /// Replace the microseconds within the second.
668 ///
669 /// ```rust
670 /// # use time_macros::time;
671 /// assert_eq!(
672 /// time!(01:02:03.004_005_006).replace_microsecond(7_008),
673 /// Ok(time!(01:02:03.007_008))
674 /// );
675 /// assert!(time!(01:02:03.004_005_006)
676 /// .replace_microsecond(1_000_000)
677 /// .is_err()); // 1_000_000 isn't a valid microsecond
678 /// ```
679 #[must_use = "This method does not mutate the original `Time`."]
680 pub const fn replace_microsecond(
681 mut self,
682 microsecond: u32,
683 ) -> Result<Self, error::ComponentRange> {
684 self.nanosecond =
685 ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32);
686 Ok(self)
687 }
688
689 /// Replace the nanoseconds within the second.
690 ///
691 /// ```rust
692 /// # use time_macros::time;
693 /// assert_eq!(
694 /// time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
695 /// Ok(time!(01:02:03.007_008_009))
696 /// );
697 /// assert!(time!(01:02:03.004_005_006)
698 /// .replace_nanosecond(1_000_000_000)
699 /// .is_err()); // 1_000_000_000 isn't a valid nanosecond
700 /// ```
701 #[must_use = "This method does not mutate the original `Time`."]
702 pub const fn replace_nanosecond(
703 mut self,
704 nanosecond: u32,
705 ) -> Result<Self, error::ComponentRange> {
706 self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
707 Ok(self)
708 }
709 // endregion replacement
710}
711
712// region: formatting & parsing
713#[cfg(feature = "formatting")]
714impl Time {
715 /// Format the `Time` using the provided [format description](crate::format_description).
716 pub fn format_into(
717 self,
718 output: &mut (impl io::Write + ?Sized),
719 format: &(impl Formattable + ?Sized),
720 ) -> Result<usize, error::Format> {
721 format.format_into(output, None, Some(self), None)
722 }
723
724 /// Format the `Time` using the provided [format description](crate::format_description).
725 ///
726 /// ```rust
727 /// # use time::format_description;
728 /// # use time_macros::time;
729 /// let format = format_description::parse("[hour]:[minute]:[second]")?;
730 /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
731 /// # Ok::<_, time::Error>(())
732 /// ```
733 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
734 format.format(None, Some(self), None)
735 }
736}
737
738#[cfg(feature = "parsing")]
739impl Time {
740 /// Parse a `Time` from the input using the provided [format
741 /// description](crate::format_description).
742 ///
743 /// ```rust
744 /// # use time::Time;
745 /// # use time_macros::{time, format_description};
746 /// let format = format_description!("[hour]:[minute]:[second]");
747 /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
748 /// # Ok::<_, time::Error>(())
749 /// ```
750 pub fn parse(
751 input: &str,
752 description: &(impl Parsable + ?Sized),
753 ) -> Result<Self, error::Parse> {
754 description.parse_time(input.as_bytes())
755 }
756}
757
758mod private {
759 #[non_exhaustive]
760 #[derive(Debug, Clone, Copy)]
761 pub struct TimeMetadata {
762 /// How many characters wide the formatted subsecond is.
763 pub(super) subsecond_width: u8,
764 /// The value to use when formatting the subsecond. Leading zeroes will be added as
765 /// necessary.
766 pub(super) subsecond_value: u32,
767 }
768}
769use private::TimeMetadata;
770
771impl SmartDisplay for Time {
772 type Metadata = TimeMetadata;
773
774 fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
775 let (subsecond_value, subsecond_width) = match self.nanosecond() {
776 nanos if nanos % 10 != 0 => (nanos, 9),
777 nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
778 nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
779 nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
780 nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
781 nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
782 nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
783 nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
784 nanos => (nanos / 100_000_000, 1),
785 };
786
787 let formatted_width = smart_display::padded_width_of!(
788 self.hour.get(),
789 ":",
790 self.minute.get() => width(2) fill('0'),
791 ":",
792 self.second.get() => width(2) fill('0'),
793 ".",
794 ) + subsecond_width;
795
796 Metadata::new(
797 formatted_width,
798 self,
799 TimeMetadata {
800 subsecond_width: subsecond_width.truncate(),
801 subsecond_value,
802 },
803 )
804 }
805
806 fn fmt_with_metadata(
807 &self,
808 f: &mut fmt::Formatter<'_>,
809 metadata: Metadata<Self>,
810 ) -> fmt::Result {
811 let subsecond_width = metadata.subsecond_width.extend();
812 let subsecond_value = metadata.subsecond_value;
813
814 f.pad_with_width(
815 metadata.unpadded_width(),
816 format_args!(
817 "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
818 self.hour, self.minute, self.second
819 ),
820 )
821 }
822}
823
824impl fmt::Display for Time {
825 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
826 SmartDisplay::fmt(self, f)
827 }
828}
829
830impl fmt::Debug for Time {
831 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
832 fmt::Display::fmt(self, f)
833 }
834}
835// endregion formatting & parsing
836
837// region: trait impls
838impl Add<Duration> for Time {
839 type Output = Self;
840
841 /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
842 ///
843 /// ```rust
844 /// # use time::ext::NumericalDuration;
845 /// # use time_macros::time;
846 /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
847 /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
848 /// ```
849 fn add(self, duration: Duration) -> Self::Output {
850 self.adjusting_add(duration).1
851 }
852}
853
854impl Add<StdDuration> for Time {
855 type Output = Self;
856
857 /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
858 ///
859 /// ```rust
860 /// # use time::ext::NumericalStdDuration;
861 /// # use time_macros::time;
862 /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
863 /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
864 /// ```
865 fn add(self, duration: StdDuration) -> Self::Output {
866 self.adjusting_add_std(duration).1
867 }
868}
869
870impl_add_assign!(Time: Duration, StdDuration);
871
872impl Sub<Duration> for Time {
873 type Output = Self;
874
875 /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
876 ///
877 /// ```rust
878 /// # use time::ext::NumericalDuration;
879 /// # use time_macros::time;
880 /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
881 /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
882 /// ```
883 fn sub(self, duration: Duration) -> Self::Output {
884 self.adjusting_sub(duration).1
885 }
886}
887
888impl Sub<StdDuration> for Time {
889 type Output = Self;
890
891 /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
892 ///
893 /// ```rust
894 /// # use time::ext::NumericalStdDuration;
895 /// # use time_macros::time;
896 /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
897 /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
898 /// ```
899 fn sub(self, duration: StdDuration) -> Self::Output {
900 self.adjusting_sub_std(duration).1
901 }
902}
903
904impl_sub_assign!(Time: Duration, StdDuration);
905
906impl Sub for Time {
907 type Output = Duration;
908
909 /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
910 /// the same calendar day.
911 ///
912 /// ```rust
913 /// # use time::ext::NumericalDuration;
914 /// # use time_macros::time;
915 /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
916 /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
917 /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
918 /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
919 /// ```
920 fn sub(self, rhs: Self) -> Self::Output {
921 let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
922 let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
923 let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
924 let nanosecond_diff =
925 self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
926
927 let seconds = hour_diff.extend::<i64>() * Second::per(Hour).cast_signed().extend::<i64>()
928 + minute_diff.extend::<i64>() * Second::per(Minute).cast_signed().extend::<i64>()
929 + second_diff.extend::<i64>();
930
931 let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
932 (
933 seconds - 1,
934 nanosecond_diff + Nanosecond::per(Second).cast_signed(),
935 )
936 } else if seconds < 0 && nanosecond_diff > 0 {
937 (
938 seconds + 1,
939 nanosecond_diff - Nanosecond::per(Second).cast_signed(),
940 )
941 } else {
942 (seconds, nanosecond_diff)
943 };
944
945 // Safety: `nanoseconds` is in range due to the overflow handling.
946 unsafe { Duration::new_unchecked(seconds, nanoseconds) }
947 }
948}
949// endregion trait impls