time/
primitive_date_time.rs

1//! The [`PrimitiveDateTime`] struct and its associated `impl`s.
2
3#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::fmt;
6use core::ops::{Add, AddAssign, Sub, SubAssign};
7use core::time::Duration as StdDuration;
8#[cfg(feature = "formatting")]
9use std::io;
10
11use powerfmt::ext::FormatterExt as _;
12use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
13
14#[cfg(feature = "formatting")]
15use crate::formatting::Formattable;
16use crate::internal_macros::{const_try, const_try_opt};
17#[cfg(feature = "parsing")]
18use crate::parsing::Parsable;
19use crate::{
20    error, util, Date, Duration, Month, OffsetDateTime, Time, UtcDateTime, UtcOffset, Weekday,
21};
22
23/// Combined date and time.
24#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
25pub struct PrimitiveDateTime {
26    date: Date,
27    time: Time,
28}
29
30impl PrimitiveDateTime {
31    /// The smallest value that can be represented by `PrimitiveDateTime`.
32    ///
33    /// Depending on `large-dates` feature flag, value of this constant may vary.
34    ///
35    /// 1. With `large-dates` disabled it is equal to `-9999-01-01 00:00:00.0`
36    /// 2. With `large-dates` enabled it is equal to `-999999-01-01 00:00:00.0`
37    ///
38    /// ```rust
39    /// # use time::PrimitiveDateTime;
40    /// # use time_macros::datetime;
41    #[cfg_attr(
42        feature = "large-dates",
43        doc = "// Assuming `large-dates` feature is enabled."
44    )]
45    #[cfg_attr(
46        feature = "large-dates",
47        doc = "assert_eq!(PrimitiveDateTime::MIN, datetime!(-999999-01-01 0:00));"
48    )]
49    #[cfg_attr(
50        not(feature = "large-dates"),
51        doc = "// Assuming `large-dates` feature is disabled."
52    )]
53    #[cfg_attr(
54        not(feature = "large-dates"),
55        doc = "assert_eq!(PrimitiveDateTime::MIN, datetime!(-9999-01-01 0:00));"
56    )]
57    /// ```
58    pub const MIN: Self = Self {
59        date: Date::MIN,
60        time: Time::MIDNIGHT,
61    };
62
63    /// The largest value that can be represented by `PrimitiveDateTime`.
64    ///
65    /// Depending on `large-dates` feature flag, value of this constant may vary.
66    ///
67    /// 1. With `large-dates` disabled it is equal to `9999-12-31 23:59:59.999_999_999`
68    /// 2. With `large-dates` enabled it is equal to `999999-12-31 23:59:59.999_999_999`
69    ///
70    /// ```rust
71    /// # use time::PrimitiveDateTime;
72    /// # use time_macros::datetime;
73    #[cfg_attr(
74        feature = "large-dates",
75        doc = "// Assuming `large-dates` feature is enabled."
76    )]
77    #[cfg_attr(
78        feature = "large-dates",
79        doc = "assert_eq!(PrimitiveDateTime::MAX, datetime!(+999999-12-31 23:59:59.999_999_999));"
80    )]
81    #[cfg_attr(
82        not(feature = "large-dates"),
83        doc = "// Assuming `large-dates` feature is disabled."
84    )]
85    #[cfg_attr(
86        not(feature = "large-dates"),
87        doc = "assert_eq!(PrimitiveDateTime::MAX, datetime!(+9999-12-31 23:59:59.999_999_999));"
88    )]
89    /// ```
90    pub const MAX: Self = Self {
91        date: Date::MAX,
92        time: Time::MAX,
93    };
94
95    /// Create a new `PrimitiveDateTime` from the provided [`Date`] and [`Time`].
96    ///
97    /// ```rust
98    /// # use time::PrimitiveDateTime;
99    /// # use time_macros::{date, datetime, time};
100    /// assert_eq!(
101    ///     PrimitiveDateTime::new(date!(2019-01-01), time!(0:00)),
102    ///     datetime!(2019-01-01 0:00),
103    /// );
104    /// ```
105    pub const fn new(date: Date, time: Time) -> Self {
106        Self { date, time }
107    }
108
109    // region: component getters
110    /// Get the [`Date`] component of the `PrimitiveDateTime`.
111    ///
112    /// ```rust
113    /// # use time_macros::{date, datetime};
114    /// assert_eq!(datetime!(2019-01-01 0:00).date(), date!(2019-01-01));
115    /// ```
116    pub const fn date(self) -> Date {
117        self.date
118    }
119
120    /// Get the [`Time`] component of the `PrimitiveDateTime`.
121    ///
122    /// ```rust
123    /// # use time_macros::{datetime, time};
124    /// assert_eq!(datetime!(2019-01-01 0:00).time(), time!(0:00));
125    /// ```
126    pub const fn time(self) -> Time {
127        self.time
128    }
129    // endregion component getters
130
131    // region: date getters
132    /// Get the year of the date.
133    ///
134    /// ```rust
135    /// # use time_macros::datetime;
136    /// assert_eq!(datetime!(2019-01-01 0:00).year(), 2019);
137    /// assert_eq!(datetime!(2019-12-31 0:00).year(), 2019);
138    /// assert_eq!(datetime!(2020-01-01 0:00).year(), 2020);
139    /// ```
140    pub const fn year(self) -> i32 {
141        self.date().year()
142    }
143
144    /// Get the month of the date.
145    ///
146    /// ```rust
147    /// # use time::Month;
148    /// # use time_macros::datetime;
149    /// assert_eq!(datetime!(2019-01-01 0:00).month(), Month::January);
150    /// assert_eq!(datetime!(2019-12-31 0:00).month(), Month::December);
151    /// ```
152    pub const fn month(self) -> Month {
153        self.date().month()
154    }
155
156    /// Get the day of the date.
157    ///
158    /// The returned value will always be in the range `1..=31`.
159    ///
160    /// ```rust
161    /// # use time_macros::datetime;
162    /// assert_eq!(datetime!(2019-01-01 0:00).day(), 1);
163    /// assert_eq!(datetime!(2019-12-31 0:00).day(), 31);
164    /// ```
165    pub const fn day(self) -> u8 {
166        self.date().day()
167    }
168
169    /// Get the day of the year.
170    ///
171    /// The returned value will always be in the range `1..=366` (`1..=365` for common years).
172    ///
173    /// ```rust
174    /// # use time_macros::datetime;
175    /// assert_eq!(datetime!(2019-01-01 0:00).ordinal(), 1);
176    /// assert_eq!(datetime!(2019-12-31 0:00).ordinal(), 365);
177    /// ```
178    pub const fn ordinal(self) -> u16 {
179        self.date().ordinal()
180    }
181
182    /// Get the ISO week number.
183    ///
184    /// The returned value will always be in the range `1..=53`.
185    ///
186    /// ```rust
187    /// # use time_macros::datetime;
188    /// assert_eq!(datetime!(2019-01-01 0:00).iso_week(), 1);
189    /// assert_eq!(datetime!(2019-10-04 0:00).iso_week(), 40);
190    /// assert_eq!(datetime!(2020-01-01 0:00).iso_week(), 1);
191    /// assert_eq!(datetime!(2020-12-31 0:00).iso_week(), 53);
192    /// assert_eq!(datetime!(2021-01-01 0:00).iso_week(), 53);
193    /// ```
194    pub const fn iso_week(self) -> u8 {
195        self.date().iso_week()
196    }
197
198    /// Get the week number where week 1 begins on the first Sunday.
199    ///
200    /// The returned value will always be in the range `0..=53`.
201    ///
202    /// ```rust
203    /// # use time_macros::datetime;
204    /// assert_eq!(datetime!(2019-01-01 0:00).sunday_based_week(), 0);
205    /// assert_eq!(datetime!(2020-01-01 0:00).sunday_based_week(), 0);
206    /// assert_eq!(datetime!(2020-12-31 0:00).sunday_based_week(), 52);
207    /// assert_eq!(datetime!(2021-01-01 0:00).sunday_based_week(), 0);
208    /// ```
209    pub const fn sunday_based_week(self) -> u8 {
210        self.date().sunday_based_week()
211    }
212
213    /// Get the week number where week 1 begins on the first Monday.
214    ///
215    /// The returned value will always be in the range `0..=53`.
216    ///
217    /// ```rust
218    /// # use time_macros::datetime;
219    /// assert_eq!(datetime!(2019-01-01 0:00).monday_based_week(), 0);
220    /// assert_eq!(datetime!(2020-01-01 0:00).monday_based_week(), 0);
221    /// assert_eq!(datetime!(2020-12-31 0:00).monday_based_week(), 52);
222    /// assert_eq!(datetime!(2021-01-01 0:00).monday_based_week(), 0);
223    /// ```
224    pub const fn monday_based_week(self) -> u8 {
225        self.date().monday_based_week()
226    }
227
228    /// Get the year, month, and day.
229    ///
230    /// ```rust
231    /// # use time::Month;
232    /// # use time_macros::datetime;
233    /// assert_eq!(
234    ///     datetime!(2019-01-01 0:00).to_calendar_date(),
235    ///     (2019, Month::January, 1)
236    /// );
237    /// ```
238    pub const fn to_calendar_date(self) -> (i32, Month, u8) {
239        self.date().to_calendar_date()
240    }
241
242    /// Get the year and ordinal day number.
243    ///
244    /// ```rust
245    /// # use time_macros::datetime;
246    /// assert_eq!(datetime!(2019-01-01 0:00).to_ordinal_date(), (2019, 1));
247    /// ```
248    pub const fn to_ordinal_date(self) -> (i32, u16) {
249        self.date().to_ordinal_date()
250    }
251
252    /// Get the ISO 8601 year, week number, and weekday.
253    ///
254    /// ```rust
255    /// # use time::Weekday::*;
256    /// # use time_macros::datetime;
257    /// assert_eq!(
258    ///     datetime!(2019-01-01 0:00).to_iso_week_date(),
259    ///     (2019, 1, Tuesday)
260    /// );
261    /// assert_eq!(
262    ///     datetime!(2019-10-04 0:00).to_iso_week_date(),
263    ///     (2019, 40, Friday)
264    /// );
265    /// assert_eq!(
266    ///     datetime!(2020-01-01 0:00).to_iso_week_date(),
267    ///     (2020, 1, Wednesday)
268    /// );
269    /// assert_eq!(
270    ///     datetime!(2020-12-31 0:00).to_iso_week_date(),
271    ///     (2020, 53, Thursday)
272    /// );
273    /// assert_eq!(
274    ///     datetime!(2021-01-01 0:00).to_iso_week_date(),
275    ///     (2020, 53, Friday)
276    /// );
277    /// ```
278    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
279        self.date().to_iso_week_date()
280    }
281
282    /// Get the weekday.
283    ///
284    /// ```rust
285    /// # use time::Weekday::*;
286    /// # use time_macros::datetime;
287    /// assert_eq!(datetime!(2019-01-01 0:00).weekday(), Tuesday);
288    /// assert_eq!(datetime!(2019-02-01 0:00).weekday(), Friday);
289    /// assert_eq!(datetime!(2019-03-01 0:00).weekday(), Friday);
290    /// assert_eq!(datetime!(2019-04-01 0:00).weekday(), Monday);
291    /// assert_eq!(datetime!(2019-05-01 0:00).weekday(), Wednesday);
292    /// assert_eq!(datetime!(2019-06-01 0:00).weekday(), Saturday);
293    /// assert_eq!(datetime!(2019-07-01 0:00).weekday(), Monday);
294    /// assert_eq!(datetime!(2019-08-01 0:00).weekday(), Thursday);
295    /// assert_eq!(datetime!(2019-09-01 0:00).weekday(), Sunday);
296    /// assert_eq!(datetime!(2019-10-01 0:00).weekday(), Tuesday);
297    /// assert_eq!(datetime!(2019-11-01 0:00).weekday(), Friday);
298    /// assert_eq!(datetime!(2019-12-01 0:00).weekday(), Sunday);
299    /// ```
300    pub const fn weekday(self) -> Weekday {
301        self.date().weekday()
302    }
303
304    /// Get the Julian day for the date. The time is not taken into account for this calculation.
305    ///
306    /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
307    /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
308    ///
309    /// ```rust
310    /// # use time_macros::datetime;
311    /// assert_eq!(datetime!(-4713-11-24 0:00).to_julian_day(), 0);
312    /// assert_eq!(datetime!(2000-01-01 0:00).to_julian_day(), 2_451_545);
313    /// assert_eq!(datetime!(2019-01-01 0:00).to_julian_day(), 2_458_485);
314    /// assert_eq!(datetime!(2019-12-31 0:00).to_julian_day(), 2_458_849);
315    /// ```
316    pub const fn to_julian_day(self) -> i32 {
317        self.date().to_julian_day()
318    }
319    // endregion date getters
320
321    // region: time getters
322    /// Get the clock hour, minute, and second.
323    ///
324    /// ```rust
325    /// # use time_macros::datetime;
326    /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms(), (0, 0, 0));
327    /// assert_eq!(datetime!(2020-01-01 23:59:59).as_hms(), (23, 59, 59));
328    /// ```
329    pub const fn as_hms(self) -> (u8, u8, u8) {
330        self.time().as_hms()
331    }
332
333    /// Get the clock hour, minute, second, and millisecond.
334    ///
335    /// ```rust
336    /// # use time_macros::datetime;
337    /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_milli(), (0, 0, 0, 0));
338    /// assert_eq!(
339    ///     datetime!(2020-01-01 23:59:59.999).as_hms_milli(),
340    ///     (23, 59, 59, 999)
341    /// );
342    /// ```
343    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
344        self.time().as_hms_milli()
345    }
346
347    /// Get the clock hour, minute, second, and microsecond.
348    ///
349    /// ```rust
350    /// # use time_macros::datetime;
351    /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_micro(), (0, 0, 0, 0));
352    /// assert_eq!(
353    ///     datetime!(2020-01-01 23:59:59.999_999).as_hms_micro(),
354    ///     (23, 59, 59, 999_999)
355    /// );
356    /// ```
357    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
358        self.time().as_hms_micro()
359    }
360
361    /// Get the clock hour, minute, second, and nanosecond.
362    ///
363    /// ```rust
364    /// # use time_macros::datetime;
365    /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_nano(), (0, 0, 0, 0));
366    /// assert_eq!(
367    ///     datetime!(2020-01-01 23:59:59.999_999_999).as_hms_nano(),
368    ///     (23, 59, 59, 999_999_999)
369    /// );
370    /// ```
371    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
372        self.time().as_hms_nano()
373    }
374
375    /// Get the clock hour.
376    ///
377    /// The returned value will always be in the range `0..24`.
378    ///
379    /// ```rust
380    /// # use time_macros::datetime;
381    /// assert_eq!(datetime!(2019-01-01 0:00).hour(), 0);
382    /// assert_eq!(datetime!(2019-01-01 23:59:59).hour(), 23);
383    /// ```
384    pub const fn hour(self) -> u8 {
385        self.time().hour()
386    }
387
388    /// Get the minute within the hour.
389    ///
390    /// The returned value will always be in the range `0..60`.
391    ///
392    /// ```rust
393    /// # use time_macros::datetime;
394    /// assert_eq!(datetime!(2019-01-01 0:00).minute(), 0);
395    /// assert_eq!(datetime!(2019-01-01 23:59:59).minute(), 59);
396    /// ```
397    pub const fn minute(self) -> u8 {
398        self.time().minute()
399    }
400
401    /// Get the second within the minute.
402    ///
403    /// The returned value will always be in the range `0..60`.
404    ///
405    /// ```rust
406    /// # use time_macros::datetime;
407    /// assert_eq!(datetime!(2019-01-01 0:00).second(), 0);
408    /// assert_eq!(datetime!(2019-01-01 23:59:59).second(), 59);
409    /// ```
410    pub const fn second(self) -> u8 {
411        self.time().second()
412    }
413
414    /// Get the milliseconds within the second.
415    ///
416    /// The returned value will always be in the range `0..1_000`.
417    ///
418    /// ```rust
419    /// # use time_macros::datetime;
420    /// assert_eq!(datetime!(2019-01-01 0:00).millisecond(), 0);
421    /// assert_eq!(datetime!(2019-01-01 23:59:59.999).millisecond(), 999);
422    /// ```
423    pub const fn millisecond(self) -> u16 {
424        self.time().millisecond()
425    }
426
427    /// Get the microseconds within the second.
428    ///
429    /// The returned value will always be in the range `0..1_000_000`.
430    ///
431    /// ```rust
432    /// # use time_macros::datetime;
433    /// assert_eq!(datetime!(2019-01-01 0:00).microsecond(), 0);
434    /// assert_eq!(
435    ///     datetime!(2019-01-01 23:59:59.999_999).microsecond(),
436    ///     999_999
437    /// );
438    /// ```
439    pub const fn microsecond(self) -> u32 {
440        self.time().microsecond()
441    }
442
443    /// Get the nanoseconds within the second.
444    ///
445    /// The returned value will always be in the range `0..1_000_000_000`.
446    ///
447    /// ```rust
448    /// # use time_macros::datetime;
449    /// assert_eq!(datetime!(2019-01-01 0:00).nanosecond(), 0);
450    /// assert_eq!(
451    ///     datetime!(2019-01-01 23:59:59.999_999_999).nanosecond(),
452    ///     999_999_999,
453    /// );
454    /// ```
455    pub const fn nanosecond(self) -> u32 {
456        self.time().nanosecond()
457    }
458    // endregion time getters
459
460    // region: attach offset
461    /// Assuming that the existing `PrimitiveDateTime` represents a moment in the provided
462    /// [`UtcOffset`], return an [`OffsetDateTime`].
463    ///
464    /// ```rust
465    /// # use time_macros::{datetime, offset};
466    /// assert_eq!(
467    ///     datetime!(2019-01-01 0:00)
468    ///         .assume_offset(offset!(UTC))
469    ///         .unix_timestamp(),
470    ///     1_546_300_800,
471    /// );
472    /// assert_eq!(
473    ///     datetime!(2019-01-01 0:00)
474    ///         .assume_offset(offset!(-1))
475    ///         .unix_timestamp(),
476    ///     1_546_304_400,
477    /// );
478    /// ```
479    pub const fn assume_offset(self, offset: UtcOffset) -> OffsetDateTime {
480        OffsetDateTime::new_in_offset(self.date, self.time, offset)
481    }
482
483    /// Assuming that the existing `PrimitiveDateTime` represents a moment in UTC, return an
484    /// [`OffsetDateTime`].
485    ///
486    /// ```rust
487    /// # use time_macros::datetime;
488    /// assert_eq!(
489    ///     datetime!(2019-01-01 0:00).assume_utc().unix_timestamp(),
490    ///     1_546_300_800,
491    /// );
492    /// ```
493    ///
494    /// **Note**: You may want a [`UtcDateTime`] instead, which can be obtained with the
495    /// [`PrimitiveDateTime::as_utc`] method.
496    pub const fn assume_utc(self) -> OffsetDateTime {
497        self.assume_offset(UtcOffset::UTC)
498    }
499
500    /// Assuming that the existing `PrimitiveDateTime` represents a moment in UTC, return a
501    /// [`UtcDateTime`].
502    ///
503    /// ```rust
504    /// # use time_macros::datetime;
505    /// assert_eq!(
506    ///     datetime!(2019-01-01 0:00).as_utc().unix_timestamp(),
507    ///     1_546_300_800,
508    /// );
509    /// ```
510    pub const fn as_utc(self) -> UtcDateTime {
511        UtcDateTime::from_primitive(self)
512    }
513    // endregion attach offset
514
515    // region: checked arithmetic
516    /// Computes `self + duration`, returning `None` if an overflow occurred.
517    ///
518    /// ```
519    /// # use time::{Date, ext::NumericalDuration};
520    /// # use time_macros::datetime;
521    /// let datetime = Date::MIN.midnight();
522    /// assert_eq!(datetime.checked_add((-2).days()), None);
523    ///
524    /// let datetime = Date::MAX.midnight();
525    /// assert_eq!(datetime.checked_add(1.days()), None);
526    ///
527    /// assert_eq!(
528    ///     datetime!(2019-11-25 15:30).checked_add(27.hours()),
529    ///     Some(datetime!(2019-11-26 18:30))
530    /// );
531    /// ```
532    pub const fn checked_add(self, duration: Duration) -> Option<Self> {
533        let (date_adjustment, time) = self.time.adjusting_add(duration);
534        let date = const_try_opt!(self.date.checked_add(duration));
535
536        Some(Self {
537            date: match date_adjustment {
538                util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
539                util::DateAdjustment::Next => const_try_opt!(date.next_day()),
540                util::DateAdjustment::None => date,
541            },
542            time,
543        })
544    }
545
546    /// Computes `self - duration`, returning `None` if an overflow occurred.
547    ///
548    /// ```
549    /// # use time::{Date, ext::NumericalDuration};
550    /// # use time_macros::datetime;
551    /// let datetime = Date::MIN.midnight();
552    /// assert_eq!(datetime.checked_sub(2.days()), None);
553    ///
554    /// let datetime = Date::MAX.midnight();
555    /// assert_eq!(datetime.checked_sub((-1).days()), None);
556    ///
557    /// assert_eq!(
558    ///     datetime!(2019-11-25 15:30).checked_sub(27.hours()),
559    ///     Some(datetime!(2019-11-24 12:30))
560    /// );
561    /// ```
562    pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
563        let (date_adjustment, time) = self.time.adjusting_sub(duration);
564        let date = const_try_opt!(self.date.checked_sub(duration));
565
566        Some(Self {
567            date: match date_adjustment {
568                util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
569                util::DateAdjustment::Next => const_try_opt!(date.next_day()),
570                util::DateAdjustment::None => date,
571            },
572            time,
573        })
574    }
575    // endregion: checked arithmetic
576
577    // region: saturating arithmetic
578    /// Computes `self + duration`, saturating value on overflow.
579    ///
580    /// ```
581    /// # use time::{PrimitiveDateTime, ext::NumericalDuration};
582    /// # use time_macros::datetime;
583    /// assert_eq!(
584    ///     PrimitiveDateTime::MIN.saturating_add((-2).days()),
585    ///     PrimitiveDateTime::MIN
586    /// );
587    ///
588    /// assert_eq!(
589    ///     PrimitiveDateTime::MAX.saturating_add(2.days()),
590    ///     PrimitiveDateTime::MAX
591    /// );
592    ///
593    /// assert_eq!(
594    ///     datetime!(2019-11-25 15:30).saturating_add(27.hours()),
595    ///     datetime!(2019-11-26 18:30)
596    /// );
597    /// ```
598    pub const fn saturating_add(self, duration: Duration) -> Self {
599        if let Some(datetime) = self.checked_add(duration) {
600            datetime
601        } else if duration.is_negative() {
602            Self::MIN
603        } else {
604            Self::MAX
605        }
606    }
607
608    /// Computes `self - duration`, saturating value on overflow.
609    ///
610    /// ```
611    /// # use time::{PrimitiveDateTime, ext::NumericalDuration};
612    /// # use time_macros::datetime;
613    /// assert_eq!(
614    ///     PrimitiveDateTime::MIN.saturating_sub(2.days()),
615    ///     PrimitiveDateTime::MIN
616    /// );
617    ///
618    /// assert_eq!(
619    ///     PrimitiveDateTime::MAX.saturating_sub((-2).days()),
620    ///     PrimitiveDateTime::MAX
621    /// );
622    ///
623    /// assert_eq!(
624    ///     datetime!(2019-11-25 15:30).saturating_sub(27.hours()),
625    ///     datetime!(2019-11-24 12:30)
626    /// );
627    /// ```
628    pub const fn saturating_sub(self, duration: Duration) -> Self {
629        if let Some(datetime) = self.checked_sub(duration) {
630            datetime
631        } else if duration.is_negative() {
632            Self::MAX
633        } else {
634            Self::MIN
635        }
636    }
637    // endregion: saturating arithmetic
638}
639
640// region: replacement
641/// Methods that replace part of the `PrimitiveDateTime`.
642impl PrimitiveDateTime {
643    /// Replace the time, preserving the date.
644    ///
645    /// ```rust
646    /// # use time_macros::{datetime, time};
647    /// assert_eq!(
648    ///     datetime!(2020-01-01 17:00).replace_time(time!(5:00)),
649    ///     datetime!(2020-01-01 5:00)
650    /// );
651    /// ```
652    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
653    pub const fn replace_time(self, time: Time) -> Self {
654        Self {
655            date: self.date,
656            time,
657        }
658    }
659
660    /// Replace the date, preserving the time.
661    ///
662    /// ```rust
663    /// # use time_macros::{datetime, date};
664    /// assert_eq!(
665    ///     datetime!(2020-01-01 12:00).replace_date(date!(2020-01-30)),
666    ///     datetime!(2020-01-30 12:00)
667    /// );
668    /// ```
669    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
670    pub const fn replace_date(self, date: Date) -> Self {
671        Self {
672            date,
673            time: self.time,
674        }
675    }
676
677    /// Replace the year. The month and day will be unchanged.
678    ///
679    /// ```rust
680    /// # use time_macros::datetime;
681    /// assert_eq!(
682    ///     datetime!(2022-02-18 12:00).replace_year(2019),
683    ///     Ok(datetime!(2019-02-18 12:00))
684    /// );
685    /// assert!(datetime!(2022-02-18 12:00).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
686    /// assert!(datetime!(2022-02-18 12:00).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
687    /// ```
688    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
689    pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
690        Ok(Self {
691            date: const_try!(self.date.replace_year(year)),
692            time: self.time,
693        })
694    }
695
696    /// Replace the month of the year.
697    ///
698    /// ```rust
699    /// # use time_macros::datetime;
700    /// # use time::Month;
701    /// assert_eq!(
702    ///     datetime!(2022-02-18 12:00).replace_month(Month::January),
703    ///     Ok(datetime!(2022-01-18 12:00))
704    /// );
705    /// assert!(datetime!(2022-01-30 12:00).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
706    /// ```
707    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
708    pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
709        Ok(Self {
710            date: const_try!(self.date.replace_month(month)),
711            time: self.time,
712        })
713    }
714
715    /// Replace the day of the month.
716    ///
717    /// ```rust
718    /// # use time_macros::datetime;
719    /// assert_eq!(
720    ///     datetime!(2022-02-18 12:00).replace_day(1),
721    ///     Ok(datetime!(2022-02-01 12:00))
722    /// );
723    /// assert!(datetime!(2022-02-18 12:00).replace_day(0).is_err()); // 00 isn't a valid day
724    /// assert!(datetime!(2022-02-18 12:00).replace_day(30).is_err()); // 30 isn't a valid day in February
725    /// ```
726    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
727    pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
728        Ok(Self {
729            date: const_try!(self.date.replace_day(day)),
730            time: self.time,
731        })
732    }
733
734    /// Replace the day of the year.
735    ///
736    /// ```rust
737    /// # use time_macros::datetime;
738    /// assert_eq!(datetime!(2022-049 12:00).replace_ordinal(1), Ok(datetime!(2022-001 12:00)));
739    /// assert!(datetime!(2022-049 12:00).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
740    /// assert!(datetime!(2022-049 12:00).replace_ordinal(366).is_err()); // 2022 isn't a leap year
741    /// ````
742    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
743    pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
744        Ok(Self {
745            date: const_try!(self.date.replace_ordinal(ordinal)),
746            time: self.time,
747        })
748    }
749
750    /// Replace the clock hour.
751    ///
752    /// ```rust
753    /// # use time_macros::datetime;
754    /// assert_eq!(
755    ///     datetime!(2022-02-18 01:02:03.004_005_006).replace_hour(7),
756    ///     Ok(datetime!(2022-02-18 07:02:03.004_005_006))
757    /// );
758    /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
759    /// ```
760    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
761    pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
762        Ok(Self {
763            date: self.date,
764            time: const_try!(self.time.replace_hour(hour)),
765        })
766    }
767
768    /// Replace the minutes within the hour.
769    ///
770    /// ```rust
771    /// # use time_macros::datetime;
772    /// assert_eq!(
773    ///     datetime!(2022-02-18 01:02:03.004_005_006).replace_minute(7),
774    ///     Ok(datetime!(2022-02-18 01:07:03.004_005_006))
775    /// );
776    /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
777    /// ```
778    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
779    pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
780        Ok(Self {
781            date: self.date,
782            time: const_try!(self.time.replace_minute(minute)),
783        })
784    }
785
786    /// Replace the seconds within the minute.
787    ///
788    /// ```rust
789    /// # use time_macros::datetime;
790    /// assert_eq!(
791    ///     datetime!(2022-02-18 01:02:03.004_005_006).replace_second(7),
792    ///     Ok(datetime!(2022-02-18 01:02:07.004_005_006))
793    /// );
794    /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
795    /// ```
796    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
797    pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
798        Ok(Self {
799            date: self.date,
800            time: const_try!(self.time.replace_second(second)),
801        })
802    }
803
804    /// Replace the milliseconds within the second.
805    ///
806    /// ```rust
807    /// # use time_macros::datetime;
808    /// assert_eq!(
809    ///     datetime!(2022-02-18 01:02:03.004_005_006).replace_millisecond(7),
810    ///     Ok(datetime!(2022-02-18 01:02:03.007))
811    /// );
812    /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
813    /// ```
814    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
815    pub const fn replace_millisecond(
816        self,
817        millisecond: u16,
818    ) -> Result<Self, error::ComponentRange> {
819        Ok(Self {
820            date: self.date,
821            time: const_try!(self.time.replace_millisecond(millisecond)),
822        })
823    }
824
825    /// Replace the microseconds within the second.
826    ///
827    /// ```rust
828    /// # use time_macros::datetime;
829    /// assert_eq!(
830    ///     datetime!(2022-02-18 01:02:03.004_005_006).replace_microsecond(7_008),
831    ///     Ok(datetime!(2022-02-18 01:02:03.007_008))
832    /// );
833    /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_microsecond(1_000_000).is_err()); // 1_000_000 isn't a valid microsecond
834    /// ```
835    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
836    pub const fn replace_microsecond(
837        self,
838        microsecond: u32,
839    ) -> Result<Self, error::ComponentRange> {
840        Ok(Self {
841            date: self.date,
842            time: const_try!(self.time.replace_microsecond(microsecond)),
843        })
844    }
845
846    /// Replace the nanoseconds within the second.
847    ///
848    /// ```rust
849    /// # use time_macros::datetime;
850    /// assert_eq!(
851    ///     datetime!(2022-02-18 01:02:03.004_005_006).replace_nanosecond(7_008_009),
852    ///     Ok(datetime!(2022-02-18 01:02:03.007_008_009))
853    /// );
854    /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_nanosecond(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond
855    /// ```
856    #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
857    pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
858        Ok(Self {
859            date: self.date,
860            time: const_try!(self.time.replace_nanosecond(nanosecond)),
861        })
862    }
863}
864// endregion replacement
865
866// region: formatting & parsing
867#[cfg(feature = "formatting")]
868impl PrimitiveDateTime {
869    /// Format the `PrimitiveDateTime` using the provided [format
870    /// description](crate::format_description).
871    pub fn format_into(
872        self,
873        output: &mut (impl io::Write + ?Sized),
874        format: &(impl Formattable + ?Sized),
875    ) -> Result<usize, error::Format> {
876        format.format_into(output, Some(self.date), Some(self.time), None)
877    }
878
879    /// Format the `PrimitiveDateTime` using the provided [format
880    /// description](crate::format_description).
881    ///
882    /// ```rust
883    /// # use time::format_description;
884    /// # use time_macros::datetime;
885    /// let format = format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")?;
886    /// assert_eq!(
887    ///     datetime!(2020-01-02 03:04:05).format(&format)?,
888    ///     "2020-01-02 03:04:05"
889    /// );
890    /// # Ok::<_, time::Error>(())
891    /// ```
892    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
893        format.format(Some(self.date), Some(self.time), None)
894    }
895}
896
897#[cfg(feature = "parsing")]
898impl PrimitiveDateTime {
899    /// Parse a `PrimitiveDateTime` from the input using the provided [format
900    /// description](crate::format_description).
901    ///
902    /// ```rust
903    /// # use time::PrimitiveDateTime;
904    /// # use time_macros::{datetime, format_description};
905    /// let format = format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
906    /// assert_eq!(
907    ///     PrimitiveDateTime::parse("2020-01-02 03:04:05", &format)?,
908    ///     datetime!(2020-01-02 03:04:05)
909    /// );
910    /// # Ok::<_, time::Error>(())
911    /// ```
912    pub fn parse(
913        input: &str,
914        description: &(impl Parsable + ?Sized),
915    ) -> Result<Self, error::Parse> {
916        description.parse_primitive_date_time(input.as_bytes())
917    }
918}
919
920impl SmartDisplay for PrimitiveDateTime {
921    type Metadata = ();
922
923    fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
924        let width = smart_display::padded_width_of!(self.date, " ", self.time);
925        Metadata::new(width, self, ())
926    }
927
928    fn fmt_with_metadata(
929        &self,
930        f: &mut fmt::Formatter<'_>,
931        metadata: Metadata<Self>,
932    ) -> fmt::Result {
933        f.pad_with_width(
934            metadata.unpadded_width(),
935            format_args!("{} {}", self.date, self.time),
936        )
937    }
938}
939
940impl fmt::Display for PrimitiveDateTime {
941    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
942        SmartDisplay::fmt(self, f)
943    }
944}
945
946impl fmt::Debug for PrimitiveDateTime {
947    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
948        fmt::Display::fmt(self, f)
949    }
950}
951// endregion formatting & parsing
952
953// region: trait impls
954impl Add<Duration> for PrimitiveDateTime {
955    type Output = Self;
956
957    /// # Panics
958    ///
959    /// This may panic if an overflow occurs.
960    fn add(self, duration: Duration) -> Self::Output {
961        self.checked_add(duration)
962            .expect("resulting value is out of range")
963    }
964}
965
966impl Add<StdDuration> for PrimitiveDateTime {
967    type Output = Self;
968
969    /// # Panics
970    ///
971    /// This may panic if an overflow occurs.
972    fn add(self, duration: StdDuration) -> Self::Output {
973        let (is_next_day, time) = self.time.adjusting_add_std(duration);
974
975        Self {
976            date: if is_next_day {
977                (self.date + duration)
978                    .next_day()
979                    .expect("resulting value is out of range")
980            } else {
981                self.date + duration
982            },
983            time,
984        }
985    }
986}
987
988impl AddAssign<Duration> for PrimitiveDateTime {
989    /// # Panics
990    ///
991    /// This may panic if an overflow occurs.
992    fn add_assign(&mut self, duration: Duration) {
993        *self = *self + duration;
994    }
995}
996
997impl AddAssign<StdDuration> for PrimitiveDateTime {
998    /// # Panics
999    ///
1000    /// This may panic if an overflow occurs.
1001    fn add_assign(&mut self, duration: StdDuration) {
1002        *self = *self + duration;
1003    }
1004}
1005
1006impl Sub<Duration> for PrimitiveDateTime {
1007    type Output = Self;
1008
1009    /// # Panics
1010    ///
1011    /// This may panic if an overflow occurs.
1012    fn sub(self, duration: Duration) -> Self::Output {
1013        self.checked_sub(duration)
1014            .expect("resulting value is out of range")
1015    }
1016}
1017
1018impl Sub<StdDuration> for PrimitiveDateTime {
1019    type Output = Self;
1020
1021    /// # Panics
1022    ///
1023    /// This may panic if an overflow occurs.
1024    fn sub(self, duration: StdDuration) -> Self::Output {
1025        let (is_previous_day, time) = self.time.adjusting_sub_std(duration);
1026
1027        Self {
1028            date: if is_previous_day {
1029                (self.date - duration)
1030                    .previous_day()
1031                    .expect("resulting value is out of range")
1032            } else {
1033                self.date - duration
1034            },
1035            time,
1036        }
1037    }
1038}
1039
1040impl SubAssign<Duration> for PrimitiveDateTime {
1041    /// # Panics
1042    ///
1043    /// This may panic if an overflow occurs.
1044    fn sub_assign(&mut self, duration: Duration) {
1045        *self = *self - duration;
1046    }
1047}
1048
1049impl SubAssign<StdDuration> for PrimitiveDateTime {
1050    /// # Panics
1051    ///
1052    /// This may panic if an overflow occurs.
1053    fn sub_assign(&mut self, duration: StdDuration) {
1054        *self = *self - duration;
1055    }
1056}
1057
1058impl Sub for PrimitiveDateTime {
1059    type Output = Duration;
1060
1061    /// # Panics
1062    ///
1063    /// This may panic if an overflow occurs.
1064    fn sub(self, rhs: Self) -> Self::Output {
1065        (self.date - rhs.date) + (self.time - rhs.time)
1066    }
1067}
1068// endregion trait impls