time/
utc_date_time.rs

1//! The [`UtcDateTime`] struct and associated `impl`s.
2
3#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::cmp::Ordering;
6use core::fmt;
7use core::ops::{Add, AddAssign, Sub, SubAssign};
8use core::time::Duration as StdDuration;
9#[cfg(feature = "formatting")]
10use std::io;
11#[cfg(feature = "std")]
12use std::time::SystemTime;
13
14use deranged::RangedI64;
15use powerfmt::ext::FormatterExt as _;
16use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
17
18use crate::convert::*;
19use crate::date::{MAX_YEAR, MIN_YEAR};
20#[cfg(feature = "formatting")]
21use crate::formatting::Formattable;
22use crate::internal_macros::{
23    cascade, const_try, const_try_opt, div_floor, ensure_ranged, expect_opt,
24};
25#[cfg(feature = "parsing")]
26use crate::parsing::Parsable;
27use crate::{
28    error, util, Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday,
29};
30
31/// The Julian day of the Unix epoch.
32const UNIX_EPOCH_JULIAN_DAY: i32 = UtcDateTime::UNIX_EPOCH.to_julian_day();
33
34/// A [`PrimitiveDateTime`] that is known to be UTC.
35///
36/// `UtcDateTime` is guaranteed to be ABI-compatible with [`PrimitiveDateTime`], meaning that
37/// transmuting from one to the other will not result in undefined behavior.
38#[repr(transparent)]
39#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub struct UtcDateTime {
41    inner: PrimitiveDateTime,
42}
43
44impl UtcDateTime {
45    /// Midnight, 1 January, 1970.
46    ///
47    /// ```rust
48    /// # use time::UtcDateTime;
49    /// # use time_macros::utc_datetime;
50    /// assert_eq!(UtcDateTime::UNIX_EPOCH, utc_datetime!(1970-01-01 0:00));
51    /// ```
52    pub const UNIX_EPOCH: Self = Self::new(
53        // Safety: `ordinal` is not zero.
54        unsafe { Date::__from_ordinal_date_unchecked(1970, 1) },
55        Time::MIDNIGHT,
56    );
57
58    /// The smallest value that can be represented by `UtcDateTime`.
59    ///
60    /// Depending on `large-dates` feature flag, value of this constant may vary.
61    ///
62    /// 1. With `large-dates` disabled it is equal to `-9999-01-01 00:00:00.0`
63    /// 2. With `large-dates` enabled it is equal to `-999999-01-01 00:00:00.0`
64    ///
65    /// ```rust
66    /// # use time::UtcDateTime;
67    /// # use time_macros::utc_datetime;
68    #[cfg_attr(
69        feature = "large-dates",
70        doc = "// Assuming `large-dates` feature is enabled."
71    )]
72    #[cfg_attr(
73        feature = "large-dates",
74        doc = "assert_eq!(UtcDateTime::MIN, utc_datetime!(-999999-01-01 0:00));"
75    )]
76    #[cfg_attr(
77        not(feature = "large-dates"),
78        doc = "// Assuming `large-dates` feature is disabled."
79    )]
80    #[cfg_attr(
81        not(feature = "large-dates"),
82        doc = "assert_eq!(UtcDateTime::MIN, utc_datetime!(-9999-01-01 0:00));"
83    )]
84    /// ```
85    pub const MIN: Self = Self::new(Date::MIN, Time::MIDNIGHT);
86
87    /// The largest value that can be represented by `UtcDateTime`.
88    ///
89    /// Depending on `large-dates` feature flag, value of this constant may vary.
90    ///
91    /// 1. With `large-dates` disabled it is equal to `9999-12-31 23:59:59.999_999_999`
92    /// 2. With `large-dates` enabled it is equal to `999999-12-31 23:59:59.999_999_999`
93    ///
94    /// ```rust
95    /// # use time::UtcDateTime;
96    /// # use time_macros::utc_datetime;
97    #[cfg_attr(
98        feature = "large-dates",
99        doc = "// Assuming `large-dates` feature is enabled."
100    )]
101    #[cfg_attr(
102        feature = "large-dates",
103        doc = "assert_eq!(UtcDateTime::MAX, utc_datetime!(+999999-12-31 23:59:59.999_999_999));"
104    )]
105    #[cfg_attr(
106        not(feature = "large-dates"),
107        doc = "// Assuming `large-dates` feature is disabled."
108    )]
109    #[cfg_attr(
110        not(feature = "large-dates"),
111        doc = "assert_eq!(UtcDateTime::MAX, utc_datetime!(+9999-12-31 23:59:59.999_999_999));"
112    )]
113    /// ```
114    pub const MAX: Self = Self::new(Date::MAX, Time::MAX);
115
116    // region: constructors
117    /// Create a new `UtcDateTime` with the current date and time.
118    ///
119    /// ```rust
120    /// # use time::UtcDateTime;
121    /// assert!(UtcDateTime::now().year() >= 2019);
122    /// ```
123    #[cfg(feature = "std")]
124    pub fn now() -> Self {
125        #[cfg(all(
126            target_family = "wasm",
127            not(any(target_os = "emscripten", target_os = "wasi")),
128            feature = "wasm-bindgen"
129        ))]
130        {
131            js_sys::Date::new_0().into()
132        }
133
134        #[cfg(not(all(
135            target_family = "wasm",
136            not(any(target_os = "emscripten", target_os = "wasi")),
137            feature = "wasm-bindgen"
138        )))]
139        SystemTime::now().into()
140    }
141
142    /// Create a new `UtcDateTime` from the provided [`Date`] and [`Time`].
143    ///
144    /// ```rust
145    /// # use time::UtcDateTime;
146    /// # use time_macros::{date, utc_datetime, time};
147    /// assert_eq!(
148    ///     UtcDateTime::new(date!(2019-01-01), time!(0:00)),
149    ///     utc_datetime!(2019-01-01 0:00),
150    /// );
151    /// ```
152    pub const fn new(date: Date, time: Time) -> Self {
153        Self {
154            inner: PrimitiveDateTime::new(date, time),
155        }
156    }
157
158    /// Create a new `UtcDateTime` from the [`PrimitiveDateTime`], assuming that the latter is UTC.
159    pub(crate) const fn from_primitive(date_time: PrimitiveDateTime) -> Self {
160        Self { inner: date_time }
161    }
162
163    /// Create a `UtcDateTime` from the provided Unix timestamp.
164    ///
165    /// ```rust
166    /// # use time::UtcDateTime;
167    /// # use time_macros::utc_datetime;
168    /// assert_eq!(
169    ///     UtcDateTime::from_unix_timestamp(0),
170    ///     Ok(UtcDateTime::UNIX_EPOCH),
171    /// );
172    /// assert_eq!(
173    ///     UtcDateTime::from_unix_timestamp(1_546_300_800),
174    ///     Ok(utc_datetime!(2019-01-01 0:00)),
175    /// );
176    /// ```
177    ///
178    /// If you have a timestamp-nanosecond pair, you can use something along the lines of the
179    /// following:
180    ///
181    /// ```rust
182    /// # use time::{Duration, UtcDateTime, ext::NumericalDuration};
183    /// let (timestamp, nanos) = (1, 500_000_000);
184    /// assert_eq!(
185    ///     UtcDateTime::from_unix_timestamp(timestamp)? + Duration::nanoseconds(nanos),
186    ///     UtcDateTime::UNIX_EPOCH + 1.5.seconds()
187    /// );
188    /// # Ok::<_, time::Error>(())
189    /// ```
190    pub const fn from_unix_timestamp(timestamp: i64) -> Result<Self, error::ComponentRange> {
191        type Timestamp =
192            RangedI64<{ UtcDateTime::MIN.unix_timestamp() }, { UtcDateTime::MAX.unix_timestamp() }>;
193        ensure_ranged!(Timestamp: timestamp);
194
195        // Use the unchecked method here, as the input validity has already been verified.
196        // Safety: The Julian day number is in range.
197        let date = unsafe {
198            Date::from_julian_day_unchecked(
199                UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second::per(Day) as i64) as i32,
200            )
201        };
202
203        let seconds_within_day = timestamp.rem_euclid(Second::per(Day) as _);
204        // Safety: All values are in range.
205        let time = unsafe {
206            Time::__from_hms_nanos_unchecked(
207                (seconds_within_day / Second::per(Hour) as i64) as _,
208                ((seconds_within_day % Second::per(Hour) as i64) / Minute::per(Hour) as i64) as _,
209                (seconds_within_day % Second::per(Minute) as i64) as _,
210                0,
211            )
212        };
213
214        Ok(Self::new(date, time))
215    }
216
217    /// Construct an `UtcDateTime` from the provided Unix timestamp (in nanoseconds).
218    ///
219    /// ```rust
220    /// # use time::UtcDateTime;
221    /// # use time_macros::utc_datetime;
222    /// assert_eq!(
223    ///     UtcDateTime::from_unix_timestamp_nanos(0),
224    ///     Ok(UtcDateTime::UNIX_EPOCH),
225    /// );
226    /// assert_eq!(
227    ///     UtcDateTime::from_unix_timestamp_nanos(1_546_300_800_000_000_000),
228    ///     Ok(utc_datetime!(2019-01-01 0:00)),
229    /// );
230    /// ```
231    pub const fn from_unix_timestamp_nanos(timestamp: i128) -> Result<Self, error::ComponentRange> {
232        let datetime = const_try!(Self::from_unix_timestamp(div_floor!(
233            timestamp,
234            Nanosecond::per(Second) as i128
235        ) as i64));
236
237        Ok(Self::new(
238            datetime.date(),
239            // Safety: `nanosecond` is in range due to `rem_euclid`.
240            unsafe {
241                Time::__from_hms_nanos_unchecked(
242                    datetime.hour(),
243                    datetime.minute(),
244                    datetime.second(),
245                    timestamp.rem_euclid(Nanosecond::per(Second) as _) as u32,
246                )
247            },
248        ))
249    }
250    // endregion constructors
251
252    // region: to_offset
253    /// Convert the `UtcDateTime` from UTC to the provided [`UtcOffset`], returning an
254    /// [`OffsetDateTime`].
255    ///
256    /// ```rust
257    /// # use time_macros::{utc_datetime, offset};
258    /// assert_eq!(
259    ///     utc_datetime!(2000-01-01 0:00)
260    ///         .to_offset(offset!(-1))
261    ///         .year(),
262    ///     1999,
263    /// );
264    ///
265    /// // Construct midnight on new year's, UTC.
266    /// let utc = utc_datetime!(2000-01-01 0:00);
267    /// let new_york = utc.to_offset(offset!(-5));
268    /// let los_angeles = utc.to_offset(offset!(-8));
269    /// assert_eq!(utc.hour(), 0);
270    /// assert_eq!(new_york.hour(), 19);
271    /// assert_eq!(los_angeles.hour(), 16);
272    /// ```
273    ///
274    /// # Panics
275    ///
276    /// This method panics if the local date-time in the new offset is outside the supported range.
277    pub const fn to_offset(self, offset: UtcOffset) -> OffsetDateTime {
278        expect_opt!(
279            self.checked_to_offset(offset),
280            "local datetime out of valid range"
281        )
282    }
283
284    /// Convert the `UtcDateTime` from UTC to the provided [`UtcOffset`], returning an
285    /// [`OffsetDateTime`]. `None` is returned if the date-time in the resulting offset is
286    /// invalid.
287    ///
288    /// ```rust
289    /// # use time::UtcDateTime;
290    /// # use time_macros::{utc_datetime, offset};
291    /// assert_eq!(
292    ///     utc_datetime!(2000-01-01 0:00)
293    ///         .checked_to_offset(offset!(-1))
294    ///         .unwrap()
295    ///         .year(),
296    ///     1999,
297    /// );
298    /// assert_eq!(
299    ///     UtcDateTime::MAX.checked_to_offset(offset!(+1)),
300    ///     None,
301    /// );
302    /// ```
303    pub const fn checked_to_offset(self, offset: UtcOffset) -> Option<OffsetDateTime> {
304        // Fast path for when no conversion is necessary.
305        if offset.is_utc() {
306            return Some(self.inner.assume_utc());
307        }
308
309        let (year, ordinal, time) = self.to_offset_raw(offset);
310
311        if year > MAX_YEAR || year < MIN_YEAR {
312            return None;
313        }
314
315        Some(OffsetDateTime::new_in_offset(
316            // Safety: `ordinal` is not zero.
317            unsafe { Date::__from_ordinal_date_unchecked(year, ordinal) },
318            time,
319            offset,
320        ))
321    }
322
323    /// Equivalent to `.to_offset(UtcOffset::UTC)`, but returning the year, ordinal, and time. This
324    /// avoids constructing an invalid [`Date`] if the new value is out of range.
325    pub(crate) const fn to_offset_raw(self, offset: UtcOffset) -> (i32, u16, Time) {
326        let mut second = self.second() as i16 + offset.seconds_past_minute() as i16;
327        let mut minute = self.minute() as i16 + offset.minutes_past_hour() as i16;
328        let mut hour = self.hour() as i8 + offset.whole_hours();
329        let (mut year, ordinal) = self.to_ordinal_date();
330        let mut ordinal = ordinal as i16;
331
332        cascade!(second in 0..Second::per(Minute) as i16 => minute);
333        cascade!(minute in 0..Minute::per(Hour) as i16 => hour);
334        cascade!(hour in 0..Hour::per(Day) as i8 => ordinal);
335        cascade!(ordinal => year);
336
337        debug_assert!(ordinal > 0);
338        debug_assert!(ordinal <= util::days_in_year(year) as i16);
339
340        (
341            year,
342            ordinal as _,
343            // Safety: The cascades above ensure the values are in range.
344            unsafe {
345                Time::__from_hms_nanos_unchecked(
346                    hour as _,
347                    minute as _,
348                    second as _,
349                    self.nanosecond(),
350                )
351            },
352        )
353    }
354    // endregion to_offset
355
356    // region: getters
357    /// Get the [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
358    ///
359    /// ```rust
360    /// # use time_macros::utc_datetime;
361    /// assert_eq!(utc_datetime!(1970-01-01 0:00).unix_timestamp(), 0);
362    /// assert_eq!(utc_datetime!(1970-01-01 1:00).unix_timestamp(), 3_600);
363    /// ```
364    pub const fn unix_timestamp(self) -> i64 {
365        let days =
366            (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second::per(Day) as i64;
367        let hours = self.hour() as i64 * Second::per(Hour) as i64;
368        let minutes = self.minute() as i64 * Second::per(Minute) as i64;
369        let seconds = self.second() as i64;
370        days + hours + minutes + seconds
371    }
372
373    /// Get the Unix timestamp in nanoseconds.
374    ///
375    /// ```rust
376    /// use time_macros::utc_datetime;
377    /// assert_eq!(utc_datetime!(1970-01-01 0:00).unix_timestamp_nanos(), 0);
378    /// assert_eq!(
379    ///     utc_datetime!(1970-01-01 1:00).unix_timestamp_nanos(),
380    ///     3_600_000_000_000,
381    /// );
382    /// ```
383    pub const fn unix_timestamp_nanos(self) -> i128 {
384        self.unix_timestamp() as i128 * Nanosecond::per(Second) as i128 + self.nanosecond() as i128
385    }
386
387    /// Get the [`Date`] component of the `UtcDateTime`.
388    ///
389    /// ```rust
390    /// # use time_macros::{date, utc_datetime};
391    /// assert_eq!(utc_datetime!(2019-01-01 0:00).date(), date!(2019-01-01));
392    /// ```
393    pub const fn date(self) -> Date {
394        self.inner.date()
395    }
396
397    /// Get the [`Time`] component of the `UtcDateTime`.
398    ///
399    /// ```rust
400    /// # use time_macros::{utc_datetime, time};
401    /// assert_eq!(utc_datetime!(2019-01-01 0:00).time(), time!(0:00));
402    /// ```
403    pub const fn time(self) -> Time {
404        self.inner.time()
405    }
406
407    // region: date getters
408    /// Get the year of the date.
409    ///
410    /// ```rust
411    /// # use time_macros::utc_datetime;
412    /// assert_eq!(utc_datetime!(2019-01-01 0:00).year(), 2019);
413    /// assert_eq!(utc_datetime!(2019-12-31 0:00).year(), 2019);
414    /// assert_eq!(utc_datetime!(2020-01-01 0:00).year(), 2020);
415    /// ```
416    pub const fn year(self) -> i32 {
417        self.date().year()
418    }
419
420    /// Get the month of the date.
421    ///
422    /// ```rust
423    /// # use time::Month;
424    /// # use time_macros::utc_datetime;
425    /// assert_eq!(utc_datetime!(2019-01-01 0:00).month(), Month::January);
426    /// assert_eq!(utc_datetime!(2019-12-31 0:00).month(), Month::December);
427    /// ```
428    pub const fn month(self) -> Month {
429        self.date().month()
430    }
431
432    /// Get the day of the date.
433    ///
434    /// The returned value will always be in the range `1..=31`.
435    ///
436    /// ```rust
437    /// # use time_macros::utc_datetime;
438    /// assert_eq!(utc_datetime!(2019-01-01 0:00).day(), 1);
439    /// assert_eq!(utc_datetime!(2019-12-31 0:00).day(), 31);
440    /// ```
441    pub const fn day(self) -> u8 {
442        self.date().day()
443    }
444
445    /// Get the day of the year.
446    ///
447    /// The returned value will always be in the range `1..=366` (`1..=365` for common years).
448    ///
449    /// ```rust
450    /// # use time_macros::utc_datetime;
451    /// assert_eq!(utc_datetime!(2019-01-01 0:00).ordinal(), 1);
452    /// assert_eq!(utc_datetime!(2019-12-31 0:00).ordinal(), 365);
453    /// ```
454    pub const fn ordinal(self) -> u16 {
455        self.date().ordinal()
456    }
457
458    /// Get the ISO week number.
459    ///
460    /// The returned value will always be in the range `1..=53`.
461    ///
462    /// ```rust
463    /// # use time_macros::utc_datetime;
464    /// assert_eq!(utc_datetime!(2019-01-01 0:00).iso_week(), 1);
465    /// assert_eq!(utc_datetime!(2019-10-04 0:00).iso_week(), 40);
466    /// assert_eq!(utc_datetime!(2020-01-01 0:00).iso_week(), 1);
467    /// assert_eq!(utc_datetime!(2020-12-31 0:00).iso_week(), 53);
468    /// assert_eq!(utc_datetime!(2021-01-01 0:00).iso_week(), 53);
469    /// ```
470    pub const fn iso_week(self) -> u8 {
471        self.date().iso_week()
472    }
473
474    /// Get the week number where week 1 begins on the first Sunday.
475    ///
476    /// The returned value will always be in the range `0..=53`.
477    ///
478    /// ```rust
479    /// # use time_macros::utc_datetime;
480    /// assert_eq!(utc_datetime!(2019-01-01 0:00).sunday_based_week(), 0);
481    /// assert_eq!(utc_datetime!(2020-01-01 0:00).sunday_based_week(), 0);
482    /// assert_eq!(utc_datetime!(2020-12-31 0:00).sunday_based_week(), 52);
483    /// assert_eq!(utc_datetime!(2021-01-01 0:00).sunday_based_week(), 0);
484    /// ```
485    pub const fn sunday_based_week(self) -> u8 {
486        self.date().sunday_based_week()
487    }
488
489    /// Get the week number where week 1 begins on the first Monday.
490    ///
491    /// The returned value will always be in the range `0..=53`.
492    ///
493    /// ```rust
494    /// # use time_macros::utc_datetime;
495    /// assert_eq!(utc_datetime!(2019-01-01 0:00).monday_based_week(), 0);
496    /// assert_eq!(utc_datetime!(2020-01-01 0:00).monday_based_week(), 0);
497    /// assert_eq!(utc_datetime!(2020-12-31 0:00).monday_based_week(), 52);
498    /// assert_eq!(utc_datetime!(2021-01-01 0:00).monday_based_week(), 0);
499    /// ```
500    pub const fn monday_based_week(self) -> u8 {
501        self.date().monday_based_week()
502    }
503
504    /// Get the year, month, and day.
505    ///
506    /// ```rust
507    /// # use time::Month;
508    /// # use time_macros::utc_datetime;
509    /// assert_eq!(
510    ///     utc_datetime!(2019-01-01 0:00).to_calendar_date(),
511    ///     (2019, Month::January, 1)
512    /// );
513    /// ```
514    pub const fn to_calendar_date(self) -> (i32, Month, u8) {
515        self.date().to_calendar_date()
516    }
517
518    /// Get the year and ordinal day number.
519    ///
520    /// ```rust
521    /// # use time_macros::utc_datetime;
522    /// assert_eq!(utc_datetime!(2019-01-01 0:00).to_ordinal_date(), (2019, 1));
523    /// ```
524    pub const fn to_ordinal_date(self) -> (i32, u16) {
525        self.date().to_ordinal_date()
526    }
527
528    /// Get the ISO 8601 year, week number, and weekday.
529    ///
530    /// ```rust
531    /// # use time::Weekday::*;
532    /// # use time_macros::utc_datetime;
533    /// assert_eq!(
534    ///     utc_datetime!(2019-01-01 0:00).to_iso_week_date(),
535    ///     (2019, 1, Tuesday)
536    /// );
537    /// assert_eq!(
538    ///     utc_datetime!(2019-10-04 0:00).to_iso_week_date(),
539    ///     (2019, 40, Friday)
540    /// );
541    /// assert_eq!(
542    ///     utc_datetime!(2020-01-01 0:00).to_iso_week_date(),
543    ///     (2020, 1, Wednesday)
544    /// );
545    /// assert_eq!(
546    ///     utc_datetime!(2020-12-31 0:00).to_iso_week_date(),
547    ///     (2020, 53, Thursday)
548    /// );
549    /// assert_eq!(
550    ///     utc_datetime!(2021-01-01 0:00).to_iso_week_date(),
551    ///     (2020, 53, Friday)
552    /// );
553    /// ```
554    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
555        self.date().to_iso_week_date()
556    }
557
558    /// Get the weekday.
559    ///
560    /// ```rust
561    /// # use time::Weekday::*;
562    /// # use time_macros::utc_datetime;
563    /// assert_eq!(utc_datetime!(2019-01-01 0:00).weekday(), Tuesday);
564    /// assert_eq!(utc_datetime!(2019-02-01 0:00).weekday(), Friday);
565    /// assert_eq!(utc_datetime!(2019-03-01 0:00).weekday(), Friday);
566    /// assert_eq!(utc_datetime!(2019-04-01 0:00).weekday(), Monday);
567    /// assert_eq!(utc_datetime!(2019-05-01 0:00).weekday(), Wednesday);
568    /// assert_eq!(utc_datetime!(2019-06-01 0:00).weekday(), Saturday);
569    /// assert_eq!(utc_datetime!(2019-07-01 0:00).weekday(), Monday);
570    /// assert_eq!(utc_datetime!(2019-08-01 0:00).weekday(), Thursday);
571    /// assert_eq!(utc_datetime!(2019-09-01 0:00).weekday(), Sunday);
572    /// assert_eq!(utc_datetime!(2019-10-01 0:00).weekday(), Tuesday);
573    /// assert_eq!(utc_datetime!(2019-11-01 0:00).weekday(), Friday);
574    /// assert_eq!(utc_datetime!(2019-12-01 0:00).weekday(), Sunday);
575    /// ```
576    pub const fn weekday(self) -> Weekday {
577        self.date().weekday()
578    }
579
580    /// Get the Julian day for the date. The time is not taken into account for this calculation.
581    ///
582    /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
583    /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
584    ///
585    /// ```rust
586    /// # use time_macros::utc_datetime;
587    /// assert_eq!(utc_datetime!(-4713-11-24 0:00).to_julian_day(), 0);
588    /// assert_eq!(utc_datetime!(2000-01-01 0:00).to_julian_day(), 2_451_545);
589    /// assert_eq!(utc_datetime!(2019-01-01 0:00).to_julian_day(), 2_458_485);
590    /// assert_eq!(utc_datetime!(2019-12-31 0:00).to_julian_day(), 2_458_849);
591    /// ```
592    pub const fn to_julian_day(self) -> i32 {
593        self.date().to_julian_day()
594    }
595    // endregion date getters
596
597    // region: time getters
598    /// Get the clock hour, minute, and second.
599    ///
600    /// ```rust
601    /// # use time_macros::utc_datetime;
602    /// assert_eq!(utc_datetime!(2020-01-01 0:00:00).as_hms(), (0, 0, 0));
603    /// assert_eq!(utc_datetime!(2020-01-01 23:59:59).as_hms(), (23, 59, 59));
604    /// ```
605    pub const fn as_hms(self) -> (u8, u8, u8) {
606        self.time().as_hms()
607    }
608
609    /// Get the clock hour, minute, second, and millisecond.
610    ///
611    /// ```rust
612    /// # use time_macros::utc_datetime;
613    /// assert_eq!(utc_datetime!(2020-01-01 0:00:00).as_hms_milli(), (0, 0, 0, 0));
614    /// assert_eq!(
615    ///     utc_datetime!(2020-01-01 23:59:59.999).as_hms_milli(),
616    ///     (23, 59, 59, 999)
617    /// );
618    /// ```
619    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
620        self.time().as_hms_milli()
621    }
622
623    /// Get the clock hour, minute, second, and microsecond.
624    ///
625    /// ```rust
626    /// # use time_macros::utc_datetime;
627    /// assert_eq!(utc_datetime!(2020-01-01 0:00:00).as_hms_micro(), (0, 0, 0, 0));
628    /// assert_eq!(
629    ///     utc_datetime!(2020-01-01 23:59:59.999_999).as_hms_micro(),
630    ///     (23, 59, 59, 999_999)
631    /// );
632    /// ```
633    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
634        self.time().as_hms_micro()
635    }
636
637    /// Get the clock hour, minute, second, and nanosecond.
638    ///
639    /// ```rust
640    /// # use time_macros::utc_datetime;
641    /// assert_eq!(utc_datetime!(2020-01-01 0:00:00).as_hms_nano(), (0, 0, 0, 0));
642    /// assert_eq!(
643    ///     utc_datetime!(2020-01-01 23:59:59.999_999_999).as_hms_nano(),
644    ///     (23, 59, 59, 999_999_999)
645    /// );
646    /// ```
647    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
648        self.time().as_hms_nano()
649    }
650
651    /// Get the clock hour.
652    ///
653    /// The returned value will always be in the range `0..24`.
654    ///
655    /// ```rust
656    /// # use time_macros::utc_datetime;
657    /// assert_eq!(utc_datetime!(2019-01-01 0:00).hour(), 0);
658    /// assert_eq!(utc_datetime!(2019-01-01 23:59:59).hour(), 23);
659    /// ```
660    pub const fn hour(self) -> u8 {
661        self.time().hour()
662    }
663
664    /// Get the minute within the hour.
665    ///
666    /// The returned value will always be in the range `0..60`.
667    ///
668    /// ```rust
669    /// # use time_macros::utc_datetime;
670    /// assert_eq!(utc_datetime!(2019-01-01 0:00).minute(), 0);
671    /// assert_eq!(utc_datetime!(2019-01-01 23:59:59).minute(), 59);
672    /// ```
673    pub const fn minute(self) -> u8 {
674        self.time().minute()
675    }
676
677    /// Get the second within the minute.
678    ///
679    /// The returned value will always be in the range `0..60`.
680    ///
681    /// ```rust
682    /// # use time_macros::utc_datetime;
683    /// assert_eq!(utc_datetime!(2019-01-01 0:00).second(), 0);
684    /// assert_eq!(utc_datetime!(2019-01-01 23:59:59).second(), 59);
685    /// ```
686    pub const fn second(self) -> u8 {
687        self.time().second()
688    }
689
690    /// Get the milliseconds within the second.
691    ///
692    /// The returned value will always be in the range `0..1_000`.
693    ///
694    /// ```rust
695    /// # use time_macros::utc_datetime;
696    /// assert_eq!(utc_datetime!(2019-01-01 0:00).millisecond(), 0);
697    /// assert_eq!(utc_datetime!(2019-01-01 23:59:59.999).millisecond(), 999);
698    /// ```
699    pub const fn millisecond(self) -> u16 {
700        self.time().millisecond()
701    }
702
703    /// Get the microseconds within the second.
704    ///
705    /// The returned value will always be in the range `0..1_000_000`.
706    ///
707    /// ```rust
708    /// # use time_macros::utc_datetime;
709    /// assert_eq!(utc_datetime!(2019-01-01 0:00).microsecond(), 0);
710    /// assert_eq!(
711    ///     utc_datetime!(2019-01-01 23:59:59.999_999).microsecond(),
712    ///     999_999
713    /// );
714    /// ```
715    pub const fn microsecond(self) -> u32 {
716        self.time().microsecond()
717    }
718
719    /// Get the nanoseconds within the second.
720    ///
721    /// The returned value will always be in the range `0..1_000_000_000`.
722    ///
723    /// ```rust
724    /// # use time_macros::utc_datetime;
725    /// assert_eq!(utc_datetime!(2019-01-01 0:00).nanosecond(), 0);
726    /// assert_eq!(
727    ///     utc_datetime!(2019-01-01 23:59:59.999_999_999).nanosecond(),
728    ///     999_999_999,
729    /// );
730    /// ```
731    pub const fn nanosecond(self) -> u32 {
732        self.time().nanosecond()
733    }
734    // endregion time getters
735    // endregion getters
736
737    // region: checked arithmetic
738    /// Computes `self + duration`, returning `None` if an overflow occurred.
739    ///
740    /// ```rust
741    /// # use time::{UtcDateTime, ext::NumericalDuration};
742    /// # use time_macros::utc_datetime;
743    /// assert_eq!(UtcDateTime::MIN.checked_add((-2).days()), None);
744    /// assert_eq!(UtcDateTime::MAX.checked_add(1.days()), None);
745    /// assert_eq!(
746    ///     utc_datetime!(2019 - 11 - 25 15:30).checked_add(27.hours()),
747    ///     Some(utc_datetime!(2019 - 11 - 26 18:30))
748    /// );
749    /// ```
750    pub const fn checked_add(self, duration: Duration) -> Option<Self> {
751        Some(Self::from_primitive(const_try_opt!(self
752            .inner
753            .checked_add(duration))))
754    }
755
756    /// Computes `self - duration`, returning `None` if an overflow occurred.
757    ///
758    /// ```rust
759    /// # use time::{UtcDateTime, ext::NumericalDuration};
760    /// # use time_macros::utc_datetime;
761    /// assert_eq!(UtcDateTime::MIN.checked_sub(2.days()), None);
762    /// assert_eq!(UtcDateTime::MAX.checked_sub((-1).days()), None);
763    /// assert_eq!(
764    ///     utc_datetime!(2019 - 11 - 25 15:30).checked_sub(27.hours()),
765    ///     Some(utc_datetime!(2019 - 11 - 24 12:30))
766    /// );
767    /// ```
768    pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
769        Some(Self::from_primitive(const_try_opt!(self
770            .inner
771            .checked_sub(duration))))
772    }
773    // endregion checked arithmetic
774
775    // region: saturating arithmetic
776    /// Computes `self + duration`, saturating value on overflow.
777    ///
778    /// ```rust
779    /// # use time::{UtcDateTime, ext::NumericalDuration};
780    /// # use time_macros::utc_datetime;
781    /// assert_eq!(
782    ///     UtcDateTime::MIN.saturating_add((-2).days()),
783    ///     UtcDateTime::MIN
784    /// );
785    /// assert_eq!(
786    ///     UtcDateTime::MAX.saturating_add(2.days()),
787    ///     UtcDateTime::MAX
788    /// );
789    /// assert_eq!(
790    ///     utc_datetime!(2019 - 11 - 25 15:30).saturating_add(27.hours()),
791    ///     utc_datetime!(2019 - 11 - 26 18:30)
792    /// );
793    /// ```
794    pub const fn saturating_add(self, duration: Duration) -> Self {
795        Self::from_primitive(self.inner.saturating_add(duration))
796    }
797
798    /// Computes `self - duration`, saturating value on overflow.
799    ///
800    /// ```rust
801    /// # use time::{UtcDateTime, ext::NumericalDuration};
802    /// # use time_macros::utc_datetime;
803    /// assert_eq!(
804    ///     UtcDateTime::MIN.saturating_sub(2.days()),
805    ///     UtcDateTime::MIN
806    /// );
807    /// assert_eq!(
808    ///     UtcDateTime::MAX.saturating_sub((-2).days()),
809    ///     UtcDateTime::MAX
810    /// );
811    /// assert_eq!(
812    ///     utc_datetime!(2019 - 11 - 25 15:30).saturating_sub(27.hours()),
813    ///     utc_datetime!(2019 - 11 - 24 12:30)
814    /// );
815    /// ```
816    pub const fn saturating_sub(self, duration: Duration) -> Self {
817        Self::from_primitive(self.inner.saturating_sub(duration))
818    }
819    // endregion saturating arithmetic
820}
821
822// region: replacement
823/// Methods that replace part of the `UtcDateTime`.
824impl UtcDateTime {
825    /// Replace the time, preserving the date.
826    ///
827    /// ```rust
828    /// # use time_macros::{utc_datetime, time};
829    /// assert_eq!(
830    ///     utc_datetime!(2020-01-01 17:00).replace_time(time!(5:00)),
831    ///     utc_datetime!(2020-01-01 5:00)
832    /// );
833    /// ```
834    #[must_use = "This method does not mutate the original `UtcDateTime`."]
835    pub const fn replace_time(self, time: Time) -> Self {
836        Self::from_primitive(self.inner.replace_time(time))
837    }
838
839    /// Replace the date, preserving the time.
840    ///
841    /// ```rust
842    /// # use time_macros::{utc_datetime, date};
843    /// assert_eq!(
844    ///     utc_datetime!(2020-01-01 12:00).replace_date(date!(2020-01-30)),
845    ///     utc_datetime!(2020-01-30 12:00)
846    /// );
847    /// ```
848    #[must_use = "This method does not mutate the original `UtcDateTime`."]
849    pub const fn replace_date(self, date: Date) -> Self {
850        Self::from_primitive(self.inner.replace_date(date))
851    }
852
853    /// Replace the year. The month and day will be unchanged.
854    ///
855    /// ```rust
856    /// # use time_macros::utc_datetime;
857    /// assert_eq!(
858    ///     utc_datetime!(2022 - 02 - 18 12:00).replace_year(2019),
859    ///     Ok(utc_datetime!(2019 - 02 - 18 12:00))
860    /// );
861    /// assert!(utc_datetime!(2022 - 02 - 18 12:00).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
862    /// assert!(utc_datetime!(2022 - 02 - 18 12:00).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
863    /// ```
864    #[must_use = "This method does not mutate the original `UtcDateTime`."]
865    pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
866        Ok(Self::from_primitive(const_try!(self
867            .inner
868            .replace_year(year))))
869    }
870
871    /// Replace the month of the year.
872    ///
873    /// ```rust
874    /// # use time_macros::utc_datetime;
875    /// # use time::Month;
876    /// assert_eq!(
877    ///     utc_datetime!(2022 - 02 - 18 12:00).replace_month(Month::January),
878    ///     Ok(utc_datetime!(2022 - 01 - 18 12:00))
879    /// );
880    /// assert!(utc_datetime!(2022 - 01 - 30 12:00).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
881    /// ```
882    #[must_use = "This method does not mutate the original `UtcDateTime`."]
883    pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
884        Ok(Self::from_primitive(const_try!(self
885            .inner
886            .replace_month(month))))
887    }
888
889    /// Replace the day of the month.
890    ///
891    /// ```rust
892    /// # use time_macros::utc_datetime;
893    /// assert_eq!(
894    ///     utc_datetime!(2022 - 02 - 18 12:00).replace_day(1),
895    ///     Ok(utc_datetime!(2022 - 02 - 01 12:00))
896    /// );
897    /// assert!(utc_datetime!(2022 - 02 - 18 12:00).replace_day(0).is_err()); // 00 isn't a valid day
898    /// assert!(utc_datetime!(2022 - 02 - 18 12:00).replace_day(30).is_err()); // 30 isn't a valid day in February
899    /// ```
900    #[must_use = "This method does not mutate the original `UtcDateTime`."]
901    pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
902        Ok(Self::from_primitive(const_try!(self
903            .inner
904            .replace_day(day))))
905    }
906
907    /// Replace the day of the year.
908    ///
909    /// ```rust
910    /// # use time_macros::utc_datetime;
911    /// assert_eq!(utc_datetime!(2022-049 12:00).replace_ordinal(1), Ok(utc_datetime!(2022-001 12:00)));
912    /// assert!(utc_datetime!(2022-049 12:00).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
913    /// assert!(utc_datetime!(2022-049 12:00).replace_ordinal(366).is_err()); // 2022 isn't a leap year
914    /// ```
915    #[must_use = "This method does not mutate the original `UtcDateTime`."]
916    pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
917        Ok(Self::from_primitive(const_try!(self
918            .inner
919            .replace_ordinal(ordinal))))
920    }
921
922    /// Replace the clock hour.
923    ///
924    /// ```rust
925    /// # use time_macros::utc_datetime;
926    /// assert_eq!(
927    ///     utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_hour(7),
928    ///     Ok(utc_datetime!(2022 - 02 - 18 07:02:03.004_005_006))
929    /// );
930    /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
931    /// ```
932    #[must_use = "This method does not mutate the original `UtcDateTime`."]
933    pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
934        Ok(Self::from_primitive(const_try!(self
935            .inner
936            .replace_hour(hour))))
937    }
938
939    /// Replace the minutes within the hour.
940    ///
941    /// ```rust
942    /// # use time_macros::utc_datetime;
943    /// assert_eq!(
944    ///     utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_minute(7),
945    ///     Ok(utc_datetime!(2022 - 02 - 18 01:07:03.004_005_006))
946    /// );
947    /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
948    /// ```
949    #[must_use = "This method does not mutate the original `UtcDateTime`."]
950    pub const fn replace_minute(
951        self,
952        sunday_based_week: u8,
953    ) -> Result<Self, error::ComponentRange> {
954        Ok(Self::from_primitive(const_try!(self
955            .inner
956            .replace_minute(sunday_based_week))))
957    }
958
959    /// Replace the seconds within the minute.
960    ///
961    /// ```rust
962    /// # use time_macros::utc_datetime;
963    /// assert_eq!(
964    ///     utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_second(7),
965    ///     Ok(utc_datetime!(2022 - 02 - 18 01:02:07.004_005_006))
966    /// );
967    /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
968    /// ```
969    #[must_use = "This method does not mutate the original `UtcDateTime`."]
970    pub const fn replace_second(
971        self,
972        monday_based_week: u8,
973    ) -> Result<Self, error::ComponentRange> {
974        Ok(Self::from_primitive(const_try!(self
975            .inner
976            .replace_second(monday_based_week))))
977    }
978
979    /// Replace the milliseconds within the second.
980    ///
981    /// ```rust
982    /// # use time_macros::utc_datetime;
983    /// assert_eq!(
984    ///     utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_millisecond(7),
985    ///     Ok(utc_datetime!(2022 - 02 - 18 01:02:03.007))
986    /// );
987    /// assert!(utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
988    /// ```
989    #[must_use = "This method does not mutate the original `UtcDateTime`."]
990    pub const fn replace_millisecond(
991        self,
992        millisecond: u16,
993    ) -> Result<Self, error::ComponentRange> {
994        Ok(Self::from_primitive(const_try!(self
995            .inner
996            .replace_millisecond(millisecond))))
997    }
998
999    /// Replace the microseconds within the second.
1000    ///
1001    /// ```rust
1002    /// # use time_macros::utc_datetime;
1003    /// assert_eq!(
1004    ///     utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_microsecond(7_008),
1005    ///     Ok(utc_datetime!(2022 - 02 - 18 01:02:03.007_008))
1006    /// );
1007    /// assert!(utc_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
1008    /// ```
1009    #[must_use = "This method does not mutate the original `UtcDateTime`."]
1010    pub const fn replace_microsecond(
1011        self,
1012        microsecond: u32,
1013    ) -> Result<Self, error::ComponentRange> {
1014        Ok(Self::from_primitive(const_try!(self
1015            .inner
1016            .replace_microsecond(microsecond))))
1017    }
1018
1019    /// Replace the nanoseconds within the second.
1020    ///
1021    /// ```rust
1022    /// # use time_macros::utc_datetime;
1023    /// assert_eq!(
1024    ///     utc_datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_nanosecond(7_008_009),
1025    ///     Ok(utc_datetime!(2022 - 02 - 18 01:02:03.007_008_009))
1026    /// );
1027    /// assert!(utc_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
1028    /// ```
1029    #[must_use = "This method does not mutate the original `UtcDateTime`."]
1030    pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1031        Ok(Self::from_primitive(const_try!(self
1032            .inner
1033            .replace_nanosecond(nanosecond))))
1034    }
1035}
1036// endregion replacement
1037
1038// region: formatting & parsing
1039#[cfg(feature = "formatting")]
1040impl UtcDateTime {
1041    /// Format the `UtcDateTime` using the provided [format
1042    /// description](crate::format_description).
1043    pub fn format_into(
1044        self,
1045        output: &mut (impl io::Write + ?Sized),
1046        format: &(impl Formattable + ?Sized),
1047    ) -> Result<usize, error::Format> {
1048        format.format_into(
1049            output,
1050            Some(self.date()),
1051            Some(self.time()),
1052            Some(UtcOffset::UTC),
1053        )
1054    }
1055
1056    /// Format the `UtcDateTime` using the provided [format
1057    /// description](crate::format_description).
1058    ///
1059    /// ```rust
1060    /// # use time::format_description;
1061    /// # use time_macros::utc_datetime;
1062    /// let format = format_description::parse(
1063    ///     "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
1064    ///          sign:mandatory]:[offset_minute]:[offset_second]",
1065    /// )?;
1066    /// assert_eq!(
1067    ///     utc_datetime!(2020-01-02 03:04:05).format(&format)?,
1068    ///     "2020-01-02 03:04:05 +00:00:00"
1069    /// );
1070    /// # Ok::<_, time::Error>(())
1071    /// ```
1072    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1073        format.format(Some(self.date()), Some(self.time()), Some(UtcOffset::UTC))
1074    }
1075}
1076
1077#[cfg(feature = "parsing")]
1078impl UtcDateTime {
1079    /// Parse an `UtcDateTime` from the input using the provided [format
1080    /// description](crate::format_description). A [`UtcOffset`] is permitted, but not required to
1081    /// be present. If present, the value will be converted to UTC.
1082    ///
1083    /// ```rust
1084    /// # use time::UtcDateTime;
1085    /// # use time_macros::{utc_datetime, format_description};
1086    /// let format = format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
1087    /// assert_eq!(
1088    ///     UtcDateTime::parse("2020-01-02 03:04:05", &format)?,
1089    ///     utc_datetime!(2020-01-02 03:04:05)
1090    /// );
1091    /// # Ok::<_, time::Error>(())
1092    /// ```
1093    pub fn parse(
1094        input: &str,
1095        description: &(impl Parsable + ?Sized),
1096    ) -> Result<Self, error::Parse> {
1097        description.parse_utc_date_time(input.as_bytes())
1098    }
1099
1100    /// A helper method to check if the `UtcDateTime` is a valid representation of a leap second.
1101    /// Leap seconds, when parsed, are represented as the preceding nanosecond. However, leap
1102    /// seconds can only occur as the last second of a month UTC.
1103    #[cfg(feature = "parsing")]
1104    pub(crate) const fn is_valid_leap_second_stand_in(self) -> bool {
1105        let dt = self.inner;
1106
1107        dt.hour() == 23
1108            && dt.minute() == 59
1109            && dt.second() == 59
1110            && dt.nanosecond() == 999_999_999
1111            && dt.day() == dt.month().length(dt.year())
1112    }
1113}
1114
1115impl SmartDisplay for UtcDateTime {
1116    type Metadata = ();
1117
1118    fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
1119        let width = smart_display::padded_width_of!(self.date(), " ", self.time(), " +00");
1120        Metadata::new(width, self, ())
1121    }
1122
1123    fn fmt_with_metadata(
1124        &self,
1125        f: &mut fmt::Formatter<'_>,
1126        metadata: Metadata<Self>,
1127    ) -> fmt::Result {
1128        f.pad_with_width(
1129            metadata.unpadded_width(),
1130            format_args!("{} {} +00", self.date(), self.time()),
1131        )
1132    }
1133}
1134
1135impl fmt::Display for UtcDateTime {
1136    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1137        SmartDisplay::fmt(self, f)
1138    }
1139}
1140
1141impl fmt::Debug for UtcDateTime {
1142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1143        fmt::Display::fmt(self, f)
1144    }
1145}
1146// endregion formatting & parsing
1147
1148// region: trait impls
1149impl Add<Duration> for UtcDateTime {
1150    type Output = Self;
1151
1152    /// # Panics
1153    ///
1154    /// This may panic if an overflow occurs.
1155    fn add(self, duration: Duration) -> Self::Output {
1156        self.inner.add(duration).as_utc()
1157    }
1158}
1159
1160impl Add<StdDuration> for UtcDateTime {
1161    type Output = Self;
1162
1163    /// # Panics
1164    ///
1165    /// This may panic if an overflow occurs.
1166    fn add(self, duration: StdDuration) -> Self::Output {
1167        self.inner.add(duration).as_utc()
1168    }
1169}
1170
1171impl AddAssign<Duration> for UtcDateTime {
1172    /// # Panics
1173    ///
1174    /// This may panic if an overflow occurs.
1175    fn add_assign(&mut self, rhs: Duration) {
1176        self.inner.add_assign(rhs);
1177    }
1178}
1179
1180impl AddAssign<StdDuration> for UtcDateTime {
1181    /// # Panics
1182    ///
1183    /// This may panic if an overflow occurs.
1184    fn add_assign(&mut self, rhs: StdDuration) {
1185        self.inner.add_assign(rhs);
1186    }
1187}
1188
1189impl Sub<Duration> for UtcDateTime {
1190    type Output = Self;
1191
1192    /// # Panics
1193    ///
1194    /// This may panic if an overflow occurs.
1195    fn sub(self, rhs: Duration) -> Self::Output {
1196        self.checked_sub(rhs)
1197            .expect("resulting value is out of range")
1198    }
1199}
1200
1201impl Sub<StdDuration> for UtcDateTime {
1202    type Output = Self;
1203
1204    /// # Panics
1205    ///
1206    /// This may panic if an overflow occurs.
1207    fn sub(self, duration: StdDuration) -> Self::Output {
1208        Self::from_primitive(self.inner.sub(duration))
1209    }
1210}
1211
1212impl SubAssign<Duration> for UtcDateTime {
1213    /// # Panics
1214    ///
1215    /// This may panic if an overflow occurs.
1216    fn sub_assign(&mut self, rhs: Duration) {
1217        self.inner.sub_assign(rhs);
1218    }
1219}
1220
1221impl SubAssign<StdDuration> for UtcDateTime {
1222    /// # Panics
1223    ///
1224    /// This may panic if an overflow occurs.
1225    fn sub_assign(&mut self, rhs: StdDuration) {
1226        self.inner.sub_assign(rhs);
1227    }
1228}
1229
1230impl Sub for UtcDateTime {
1231    type Output = Duration;
1232
1233    /// # Panics
1234    ///
1235    /// This may panic if an overflow occurs.
1236    fn sub(self, rhs: Self) -> Self::Output {
1237        self.inner.sub(rhs.inner)
1238    }
1239}
1240
1241#[cfg(feature = "std")]
1242impl Sub<SystemTime> for UtcDateTime {
1243    type Output = Duration;
1244
1245    /// # Panics
1246    ///
1247    /// This may panic if an overflow occurs.
1248    fn sub(self, rhs: SystemTime) -> Self::Output {
1249        self - Self::from(rhs)
1250    }
1251}
1252
1253#[cfg(feature = "std")]
1254impl Sub<UtcDateTime> for SystemTime {
1255    type Output = Duration;
1256
1257    /// # Panics
1258    ///
1259    /// This may panic if an overflow occurs.
1260    fn sub(self, rhs: UtcDateTime) -> Self::Output {
1261        UtcDateTime::from(self) - rhs
1262    }
1263}
1264
1265impl Sub<OffsetDateTime> for UtcDateTime {
1266    type Output = Duration;
1267
1268    /// # Panics
1269    ///
1270    /// This may panic if an overflow occurs.
1271    fn sub(self, rhs: OffsetDateTime) -> Self::Output {
1272        OffsetDateTime::from(self) - rhs
1273    }
1274}
1275
1276impl Sub<UtcDateTime> for OffsetDateTime {
1277    type Output = Duration;
1278
1279    /// # Panics
1280    ///
1281    /// This may panic if an overflow occurs.
1282    fn sub(self, rhs: UtcDateTime) -> Self::Output {
1283        self - Self::from(rhs)
1284    }
1285}
1286
1287#[cfg(feature = "std")]
1288impl PartialEq<SystemTime> for UtcDateTime {
1289    fn eq(&self, rhs: &SystemTime) -> bool {
1290        self == &Self::from(*rhs)
1291    }
1292}
1293
1294#[cfg(feature = "std")]
1295impl PartialEq<UtcDateTime> for SystemTime {
1296    fn eq(&self, rhs: &UtcDateTime) -> bool {
1297        &UtcDateTime::from(*self) == rhs
1298    }
1299}
1300
1301impl PartialEq<OffsetDateTime> for UtcDateTime {
1302    fn eq(&self, other: &OffsetDateTime) -> bool {
1303        OffsetDateTime::from(*self) == *other
1304    }
1305}
1306
1307impl PartialEq<UtcDateTime> for OffsetDateTime {
1308    fn eq(&self, other: &UtcDateTime) -> bool {
1309        *self == Self::from(*other)
1310    }
1311}
1312
1313#[cfg(feature = "std")]
1314impl PartialOrd<SystemTime> for UtcDateTime {
1315    fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> {
1316        self.partial_cmp(&Self::from(*other))
1317    }
1318}
1319
1320#[cfg(feature = "std")]
1321impl PartialOrd<UtcDateTime> for SystemTime {
1322    fn partial_cmp(&self, other: &UtcDateTime) -> Option<Ordering> {
1323        UtcDateTime::from(*self).partial_cmp(other)
1324    }
1325}
1326
1327impl PartialOrd<OffsetDateTime> for UtcDateTime {
1328    fn partial_cmp(&self, other: &OffsetDateTime) -> Option<Ordering> {
1329        OffsetDateTime::from(*self).partial_cmp(other)
1330    }
1331}
1332
1333impl PartialOrd<UtcDateTime> for OffsetDateTime {
1334    fn partial_cmp(&self, other: &UtcDateTime) -> Option<Ordering> {
1335        self.partial_cmp(&Self::from(*other))
1336    }
1337}
1338
1339#[cfg(feature = "std")]
1340impl From<SystemTime> for UtcDateTime {
1341    fn from(system_time: SystemTime) -> Self {
1342        match system_time.duration_since(SystemTime::UNIX_EPOCH) {
1343            Ok(duration) => Self::UNIX_EPOCH + duration,
1344            Err(err) => Self::UNIX_EPOCH - err.duration(),
1345        }
1346    }
1347}
1348
1349#[cfg(feature = "std")]
1350impl From<UtcDateTime> for SystemTime {
1351    fn from(datetime: UtcDateTime) -> Self {
1352        let duration = datetime - UtcDateTime::UNIX_EPOCH;
1353
1354        if duration.is_zero() {
1355            Self::UNIX_EPOCH
1356        } else if duration.is_positive() {
1357            Self::UNIX_EPOCH + duration.unsigned_abs()
1358        } else {
1359            debug_assert!(duration.is_negative());
1360            Self::UNIX_EPOCH - duration.unsigned_abs()
1361        }
1362    }
1363}
1364
1365impl From<OffsetDateTime> for UtcDateTime {
1366    /// # Panics
1367    ///
1368    /// This may panic if an overflow occurs.
1369    fn from(datetime: OffsetDateTime) -> Self {
1370        datetime.to_utc()
1371    }
1372}
1373
1374impl From<UtcDateTime> for OffsetDateTime {
1375    /// # Panics
1376    ///
1377    /// This may panic if an overflow occurs.
1378    fn from(datetime: UtcDateTime) -> Self {
1379        datetime.inner.assume_utc()
1380    }
1381}
1382
1383#[cfg(all(
1384    target_family = "wasm",
1385    not(any(target_os = "emscripten", target_os = "wasi")),
1386    feature = "wasm-bindgen"
1387))]
1388impl From<js_sys::Date> for UtcDateTime {
1389    /// # Panics
1390    ///
1391    /// This may panic if the timestamp can not be represented.
1392    fn from(js_date: js_sys::Date) -> Self {
1393        // get_time() returns milliseconds
1394        let timestamp_nanos = (js_date.get_time() * Nanosecond::per(Millisecond) as f64) as i128;
1395        Self::from_unix_timestamp_nanos(timestamp_nanos)
1396            .expect("invalid timestamp: Timestamp cannot fit in range")
1397    }
1398}
1399
1400#[cfg(all(
1401    target_family = "wasm",
1402    not(any(target_os = "emscripten", target_os = "wasi")),
1403    feature = "wasm-bindgen"
1404))]
1405impl From<UtcDateTime> for js_sys::Date {
1406    fn from(datetime: UtcDateTime) -> Self {
1407        use num_conv::prelude::*;
1408
1409        // new Date() takes milliseconds
1410        let timestamp = (datetime.unix_timestamp_nanos()
1411            / Nanosecond::per(Millisecond).cast_signed().extend::<i128>())
1412            as f64;
1413        Self::new(&timestamp.into())
1414    }
1415}
1416// endregion trait impls