time/
offset_date_time.rs

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