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