Skip to main content

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