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