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