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