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(Minute) as i16 => minute);
311        cascade!(second in 0..Second::per(Minute) as i16 => minute);
312        cascade!(minute in 0..Minute::per(Hour) as i16 => hour);
313        cascade!(minute in 0..Minute::per(Hour) as i16 => hour);
314        cascade!(hour in 0..Hour::per(Day) as i8 => ordinal);
315        cascade!(hour in 0..Hour::per(Day) as i8 => 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(Day) as i64) as i32,
381            )
382        };
383
384        let seconds_within_day = timestamp.rem_euclid(Second::per(Day) as i64);
385        // Safety: All values are in range.
386        let time = unsafe {
387            Time::__from_hms_nanos_unchecked(
388                (seconds_within_day / Second::per(Hour) as i64) as u8,
389                ((seconds_within_day % Second::per(Hour) as i64) / Minute::per(Hour) as i64) as u8,
390                (seconds_within_day % Second::per(Minute) as i64) as u8,
391                0,
392            )
393        };
394
395        Ok(Self::new_in_offset(date, time, UtcOffset::UTC))
396    }
397
398    /// Construct an `OffsetDateTime` from the provided Unix timestamp (in nanoseconds). Calling
399    /// `.offset()` on the resulting value is guaranteed to return UTC.
400    ///
401    /// ```rust
402    /// # use time::OffsetDateTime;
403    /// # use time_macros::datetime;
404    /// assert_eq!(
405    ///     OffsetDateTime::from_unix_timestamp_nanos(0),
406    ///     Ok(OffsetDateTime::UNIX_EPOCH),
407    /// );
408    /// assert_eq!(
409    ///     OffsetDateTime::from_unix_timestamp_nanos(1_546_300_800_000_000_000),
410    ///     Ok(datetime!(2019-01-01 0:00 UTC)),
411    /// );
412    /// ```
413    pub const fn from_unix_timestamp_nanos(timestamp: i128) -> Result<Self, error::ComponentRange> {
414        let datetime = const_try!(Self::from_unix_timestamp(div_floor!(
415            timestamp,
416            Nanosecond::per(Second) as i128
417        ) as i64));
418
419        Ok(Self::new_in_offset(
420            datetime.date(),
421            // Safety: `nanosecond` is in range due to `rem_euclid`.
422            unsafe {
423                Time::__from_hms_nanos_unchecked(
424                    datetime.hour(),
425                    datetime.minute(),
426                    datetime.second(),
427                    timestamp.rem_euclid(Nanosecond::per(Second) as i128) as u32,
428                )
429            },
430            UtcOffset::UTC,
431        ))
432    }
433
434    /// Get the [`UtcOffset`].
435    ///
436    /// ```rust
437    /// # use time_macros::{datetime, offset};
438    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).offset(), offset!(UTC));
439    /// assert_eq!(datetime!(2019-01-01 0:00 +1).offset(), offset!(+1));
440    /// ```
441    pub const fn offset(self) -> UtcOffset {
442        self.offset
443    }
444
445    /// Get the [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
446    ///
447    /// ```rust
448    /// # use time_macros::datetime;
449    /// assert_eq!(datetime!(1970-01-01 0:00 UTC).unix_timestamp(), 0);
450    /// assert_eq!(datetime!(1970-01-01 0:00 -1).unix_timestamp(), 3_600);
451    /// ```
452    pub const fn unix_timestamp(self) -> i64 {
453        let days =
454            (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second::per(Day) as i64;
455        let hours = self.hour() as i64 * Second::per(Hour) as i64;
456        let minutes = self.minute() as i64 * Second::per(Minute) as i64;
457        let seconds = self.second() as i64;
458        let offset_seconds = self.offset.whole_seconds() as i64;
459        days + hours + minutes + seconds - offset_seconds
460    }
461
462    /// Get the Unix timestamp in nanoseconds.
463    ///
464    /// ```rust
465    /// use time_macros::datetime;
466    /// assert_eq!(datetime!(1970-01-01 0:00 UTC).unix_timestamp_nanos(), 0);
467    /// assert_eq!(
468    ///     datetime!(1970-01-01 0:00 -1).unix_timestamp_nanos(),
469    ///     3_600_000_000_000,
470    /// );
471    /// ```
472    pub const fn unix_timestamp_nanos(self) -> i128 {
473        self.unix_timestamp() as i128 * Nanosecond::per(Second) as i128 + self.nanosecond() as i128
474    }
475
476    /// Get the [`PrimitiveDateTime`] in the stored offset.
477    pub(crate) const fn date_time(self) -> PrimitiveDateTime {
478        self.local_date_time
479    }
480
481    /// Get the [`Date`] in the stored offset.
482    ///
483    /// ```rust
484    /// # use time_macros::{date, datetime, offset};
485    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).date(), date!(2019-01-01));
486    /// assert_eq!(
487    ///     datetime!(2019-01-01 0:00 UTC)
488    ///         .to_offset(offset!(-1))
489    ///         .date(),
490    ///     date!(2018-12-31),
491    /// );
492    /// ```
493    pub const fn date(self) -> Date {
494        self.date_time().date()
495    }
496
497    /// Get the [`Time`] in the stored offset.
498    ///
499    /// ```rust
500    /// # use time_macros::{datetime, offset, time};
501    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).time(), time!(0:00));
502    /// assert_eq!(
503    ///     datetime!(2019-01-01 0:00 UTC)
504    ///         .to_offset(offset!(-1))
505    ///         .time(),
506    ///     time!(23:00)
507    /// );
508    /// ```
509    pub const fn time(self) -> Time {
510        self.date_time().time()
511    }
512
513    /// Get the year of the date in the stored offset.
514    ///
515    /// ```rust
516    /// # use time_macros::{datetime, offset};
517    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).year(), 2019);
518    /// assert_eq!(
519    ///     datetime!(2019-12-31 23:00 UTC)
520    ///         .to_offset(offset!(+1))
521    ///         .year(),
522    ///     2020,
523    /// );
524    /// assert_eq!(datetime!(2020-01-01 0:00 UTC).year(), 2020);
525    /// ```
526    pub const fn year(self) -> i32 {
527        self.date().year()
528    }
529
530    /// Get the month of the date in the stored offset.
531    ///
532    /// ```rust
533    /// # use time::Month;
534    /// # use time_macros::{datetime, offset};
535    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).month(), Month::January);
536    /// assert_eq!(
537    ///     datetime!(2019-12-31 23:00 UTC)
538    ///         .to_offset(offset!(+1))
539    ///         .month(),
540    ///     Month::January,
541    /// );
542    /// ```
543    pub const fn month(self) -> Month {
544        self.date().month()
545    }
546
547    /// Get the day of the date in the stored offset.
548    ///
549    /// The returned value will always be in the range `1..=31`.
550    ///
551    /// ```rust
552    /// # use time_macros::{datetime, offset};
553    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).day(), 1);
554    /// assert_eq!(
555    ///     datetime!(2019-12-31 23:00 UTC)
556    ///         .to_offset(offset!(+1))
557    ///         .day(),
558    ///     1,
559    /// );
560    /// ```
561    pub const fn day(self) -> u8 {
562        self.date().day()
563    }
564
565    /// Get the day of the year of the date in the stored offset.
566    ///
567    /// The returned value will always be in the range `1..=366`.
568    ///
569    /// ```rust
570    /// # use time_macros::{datetime, offset};
571    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).ordinal(), 1);
572    /// assert_eq!(
573    ///     datetime!(2019-12-31 23:00 UTC)
574    ///         .to_offset(offset!(+1))
575    ///         .ordinal(),
576    ///     1,
577    /// );
578    /// ```
579    pub const fn ordinal(self) -> u16 {
580        self.date().ordinal()
581    }
582
583    /// Get the ISO week number of the date in the stored offset.
584    ///
585    /// The returned value will always be in the range `1..=53`.
586    ///
587    /// ```rust
588    /// # use time_macros::datetime;
589    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).iso_week(), 1);
590    /// assert_eq!(datetime!(2020-01-01 0:00 UTC).iso_week(), 1);
591    /// assert_eq!(datetime!(2020-12-31 0:00 UTC).iso_week(), 53);
592    /// assert_eq!(datetime!(2021-01-01 0:00 UTC).iso_week(), 53);
593    /// ```
594    pub const fn iso_week(self) -> u8 {
595        self.date().iso_week()
596    }
597
598    /// Get the week number where week 1 begins on the first Sunday.
599    ///
600    /// The returned value will always be in the range `0..=53`.
601    ///
602    /// ```rust
603    /// # use time_macros::datetime;
604    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).sunday_based_week(), 0);
605    /// assert_eq!(datetime!(2020-01-01 0:00 UTC).sunday_based_week(), 0);
606    /// assert_eq!(datetime!(2020-12-31 0:00 UTC).sunday_based_week(), 52);
607    /// assert_eq!(datetime!(2021-01-01 0:00 UTC).sunday_based_week(), 0);
608    /// ```
609    pub const fn sunday_based_week(self) -> u8 {
610        self.date().sunday_based_week()
611    }
612
613    /// Get the week number where week 1 begins on the first Monday.
614    ///
615    /// The returned value will always be in the range `0..=53`.
616    ///
617    /// ```rust
618    /// # use time_macros::datetime;
619    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).monday_based_week(), 0);
620    /// assert_eq!(datetime!(2020-01-01 0:00 UTC).monday_based_week(), 0);
621    /// assert_eq!(datetime!(2020-12-31 0:00 UTC).monday_based_week(), 52);
622    /// assert_eq!(datetime!(2021-01-01 0:00 UTC).monday_based_week(), 0);
623    /// ```
624    pub const fn monday_based_week(self) -> u8 {
625        self.date().monday_based_week()
626    }
627
628    /// Get the year, month, and day.
629    ///
630    /// ```rust
631    /// # use time::Month;
632    /// # use time_macros::datetime;
633    /// assert_eq!(
634    ///     datetime!(2019-01-01 0:00 UTC).to_calendar_date(),
635    ///     (2019, Month::January, 1)
636    /// );
637    /// ```
638    pub const fn to_calendar_date(self) -> (i32, Month, u8) {
639        self.date().to_calendar_date()
640    }
641
642    /// Get the year and ordinal day number.
643    ///
644    /// ```rust
645    /// # use time_macros::datetime;
646    /// assert_eq!(
647    ///     datetime!(2019-01-01 0:00 UTC).to_ordinal_date(),
648    ///     (2019, 1)
649    /// );
650    /// ```
651    pub const fn to_ordinal_date(self) -> (i32, u16) {
652        self.date().to_ordinal_date()
653    }
654
655    /// Get the ISO 8601 year, week number, and weekday.
656    ///
657    /// ```rust
658    /// # use time::Weekday::*;
659    /// # use time_macros::datetime;
660    /// assert_eq!(
661    ///     datetime!(2019-01-01 0:00 UTC).to_iso_week_date(),
662    ///     (2019, 1, Tuesday)
663    /// );
664    /// assert_eq!(
665    ///     datetime!(2019-10-04 0:00 UTC).to_iso_week_date(),
666    ///     (2019, 40, Friday)
667    /// );
668    /// assert_eq!(
669    ///     datetime!(2020-01-01 0:00 UTC).to_iso_week_date(),
670    ///     (2020, 1, Wednesday)
671    /// );
672    /// assert_eq!(
673    ///     datetime!(2020-12-31 0:00 UTC).to_iso_week_date(),
674    ///     (2020, 53, Thursday)
675    /// );
676    /// assert_eq!(
677    ///     datetime!(2021-01-01 0:00 UTC).to_iso_week_date(),
678    ///     (2020, 53, Friday)
679    /// );
680    /// ```
681    pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
682        self.date().to_iso_week_date()
683    }
684
685    /// Get the weekday of the date in the stored offset.
686    ///
687    /// ```rust
688    /// # use time::Weekday::*;
689    /// # use time_macros::datetime;
690    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).weekday(), Tuesday);
691    /// assert_eq!(datetime!(2019-02-01 0:00 UTC).weekday(), Friday);
692    /// assert_eq!(datetime!(2019-03-01 0:00 UTC).weekday(), Friday);
693    /// ```
694    pub const fn weekday(self) -> Weekday {
695        self.date().weekday()
696    }
697
698    /// Get the Julian day for the date. The time is not taken into account for this calculation.
699    ///
700    /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
701    /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
702    ///
703    /// ```rust
704    /// # use time_macros::datetime;
705    /// assert_eq!(datetime!(-4713-11-24 0:00 UTC).to_julian_day(), 0);
706    /// assert_eq!(datetime!(2000-01-01 0:00 UTC).to_julian_day(), 2_451_545);
707    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).to_julian_day(), 2_458_485);
708    /// assert_eq!(datetime!(2019-12-31 0:00 UTC).to_julian_day(), 2_458_849);
709    /// ```
710    pub const fn to_julian_day(self) -> i32 {
711        self.date().to_julian_day()
712    }
713
714    /// Get the clock hour, minute, and second.
715    ///
716    /// ```rust
717    /// # use time_macros::datetime;
718    /// assert_eq!(datetime!(2020-01-01 0:00:00 UTC).to_hms(), (0, 0, 0));
719    /// assert_eq!(datetime!(2020-01-01 23:59:59 UTC).to_hms(), (23, 59, 59));
720    /// ```
721    pub const fn to_hms(self) -> (u8, u8, u8) {
722        self.time().as_hms()
723    }
724
725    /// Get the clock hour, minute, second, and millisecond.
726    ///
727    /// ```rust
728    /// # use time_macros::datetime;
729    /// assert_eq!(
730    ///     datetime!(2020-01-01 0:00:00 UTC).to_hms_milli(),
731    ///     (0, 0, 0, 0)
732    /// );
733    /// assert_eq!(
734    ///     datetime!(2020-01-01 23:59:59.999 UTC).to_hms_milli(),
735    ///     (23, 59, 59, 999)
736    /// );
737    /// ```
738    pub const fn to_hms_milli(self) -> (u8, u8, u8, u16) {
739        self.time().as_hms_milli()
740    }
741
742    /// Get the clock hour, minute, second, and microsecond.
743    ///
744    /// ```rust
745    /// # use time_macros::datetime;
746    /// assert_eq!(
747    ///     datetime!(2020-01-01 0:00:00 UTC).to_hms_micro(),
748    ///     (0, 0, 0, 0)
749    /// );
750    /// assert_eq!(
751    ///     datetime!(2020-01-01 23:59:59.999_999 UTC).to_hms_micro(),
752    ///     (23, 59, 59, 999_999)
753    /// );
754    /// ```
755    pub const fn to_hms_micro(self) -> (u8, u8, u8, u32) {
756        self.time().as_hms_micro()
757    }
758
759    /// Get the clock hour, minute, second, and nanosecond.
760    ///
761    /// ```rust
762    /// # use time_macros::datetime;
763    /// assert_eq!(
764    ///     datetime!(2020-01-01 0:00:00 UTC).to_hms_nano(),
765    ///     (0, 0, 0, 0)
766    /// );
767    /// assert_eq!(
768    ///     datetime!(2020-01-01 23:59:59.999_999_999 UTC).to_hms_nano(),
769    ///     (23, 59, 59, 999_999_999)
770    /// );
771    /// ```
772    pub const fn to_hms_nano(self) -> (u8, u8, u8, u32) {
773        self.time().as_hms_nano()
774    }
775
776    /// Get the clock hour in the stored offset.
777    ///
778    /// The returned value will always be in the range `0..24`.
779    ///
780    /// ```rust
781    /// # use time_macros::{datetime, offset};
782    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).hour(), 0);
783    /// assert_eq!(
784    ///     datetime!(2019-01-01 23:59:59 UTC)
785    ///         .to_offset(offset!(-2))
786    ///         .hour(),
787    ///     21,
788    /// );
789    /// ```
790    pub const fn hour(self) -> u8 {
791        self.time().hour()
792    }
793
794    /// Get the minute within the hour in the stored offset.
795    ///
796    /// The returned value will always be in the range `0..60`.
797    ///
798    /// ```rust
799    /// # use time_macros::{datetime, offset};
800    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).minute(), 0);
801    /// assert_eq!(
802    ///     datetime!(2019-01-01 23:59:59 UTC)
803    ///         .to_offset(offset!(+0:30))
804    ///         .minute(),
805    ///     29,
806    /// );
807    /// ```
808    pub const fn minute(self) -> u8 {
809        self.time().minute()
810    }
811
812    /// Get the second within the minute in the stored offset.
813    ///
814    /// The returned value will always be in the range `0..60`.
815    ///
816    /// ```rust
817    /// # use time_macros::{datetime, offset};
818    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).second(), 0);
819    /// assert_eq!(
820    ///     datetime!(2019-01-01 23:59:59 UTC)
821    ///         .to_offset(offset!(+0:00:30))
822    ///         .second(),
823    ///     29,
824    /// );
825    /// ```
826    pub const fn second(self) -> u8 {
827        self.time().second()
828    }
829
830    // Because a `UtcOffset` is limited in resolution to one second, any subsecond value will not
831    // change when adjusting for the offset.
832
833    /// Get the milliseconds within the second in the stored offset.
834    ///
835    /// The returned value will always be in the range `0..1_000`.
836    ///
837    /// ```rust
838    /// # use time_macros::datetime;
839    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).millisecond(), 0);
840    /// assert_eq!(datetime!(2019-01-01 23:59:59.999 UTC).millisecond(), 999);
841    /// ```
842    pub const fn millisecond(self) -> u16 {
843        self.time().millisecond()
844    }
845
846    /// Get the microseconds within the second in the stored offset.
847    ///
848    /// The returned value will always be in the range `0..1_000_000`.
849    ///
850    /// ```rust
851    /// # use time_macros::datetime;
852    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).microsecond(), 0);
853    /// assert_eq!(
854    ///     datetime!(2019-01-01 23:59:59.999_999 UTC).microsecond(),
855    ///     999_999,
856    /// );
857    /// ```
858    pub const fn microsecond(self) -> u32 {
859        self.time().microsecond()
860    }
861
862    /// Get the nanoseconds within the second in the stored offset.
863    ///
864    /// The returned value will always be in the range `0..1_000_000_000`.
865    ///
866    /// ```rust
867    /// # use time_macros::datetime;
868    /// assert_eq!(datetime!(2019-01-01 0:00 UTC).nanosecond(), 0);
869    /// assert_eq!(
870    ///     datetime!(2019-01-01 23:59:59.999_999_999 UTC).nanosecond(),
871    ///     999_999_999,
872    /// );
873    /// ```
874    pub const fn nanosecond(self) -> u32 {
875        self.time().nanosecond()
876    }
877
878    /// Computes `self + duration`, returning `None` if an overflow occurred.
879    ///
880    /// ```
881    /// # use time::{Date, ext::NumericalDuration};
882    /// # use time_macros::{datetime, offset};
883    /// let datetime = Date::MIN.midnight().assume_offset(offset!(+10));
884    /// assert_eq!(datetime.checked_add((-2).days()), None);
885    ///
886    /// let datetime = Date::MAX.midnight().assume_offset(offset!(+10));
887    /// assert_eq!(datetime.checked_add(2.days()), None);
888    ///
889    /// assert_eq!(
890    ///     datetime!(2019-11-25 15:30 +10).checked_add(27.hours()),
891    ///     Some(datetime!(2019-11-26 18:30 +10))
892    /// );
893    /// ```
894    pub const fn checked_add(self, duration: Duration) -> Option<Self> {
895        Some(const_try_opt!(self.date_time().checked_add(duration)).assume_offset(self.offset()))
896    }
897
898    /// Computes `self - duration`, returning `None` if an overflow occurred.
899    ///
900    /// ```
901    /// # use time::{Date, ext::NumericalDuration};
902    /// # use time_macros::{datetime, offset};
903    /// let datetime = Date::MIN.midnight().assume_offset(offset!(+10));
904    /// assert_eq!(datetime.checked_sub(2.days()), None);
905    ///
906    /// let datetime = Date::MAX.midnight().assume_offset(offset!(+10));
907    /// assert_eq!(datetime.checked_sub((-2).days()), None);
908    ///
909    /// assert_eq!(
910    ///     datetime!(2019-11-25 15:30 +10).checked_sub(27.hours()),
911    ///     Some(datetime!(2019-11-24 12:30 +10))
912    /// );
913    /// ```
914    pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
915        Some(const_try_opt!(self.date_time().checked_sub(duration)).assume_offset(self.offset()))
916    }
917
918    /// Computes `self + duration`, saturating value on overflow.
919    ///
920    /// ```
921    /// # use time::ext::NumericalDuration;
922    /// # use time_macros::datetime;
923    /// assert_eq!(
924    #[cfg_attr(
925        feature = "large-dates",
926        doc = "    datetime!(-999999-01-01 0:00 +10).saturating_add((-2).days()),"
927    )]
928    #[cfg_attr(feature = "large-dates", doc = "    datetime!(-999999-01-01 0:00 +10)")]
929    #[cfg_attr(
930        not(feature = "large-dates"),
931        doc = "    datetime!(-9999-01-01 0:00 +10).saturating_add((-2).days()),"
932    )]
933    #[cfg_attr(
934        not(feature = "large-dates"),
935        doc = "    datetime!(-9999-01-01 0:00 +10)"
936    )]
937    /// );
938    ///
939    /// assert_eq!(
940    #[cfg_attr(
941        feature = "large-dates",
942        doc = "    datetime!(+999999-12-31 23:59:59.999_999_999 +10).saturating_add(2.days()),"
943    )]
944    #[cfg_attr(
945        feature = "large-dates",
946        doc = "    datetime!(+999999-12-31 23:59:59.999_999_999 +10)"
947    )]
948    #[cfg_attr(
949        not(feature = "large-dates"),
950        doc = "    datetime!(+9999-12-31 23:59:59.999_999_999 +10).saturating_add(2.days()),"
951    )]
952    #[cfg_attr(
953        not(feature = "large-dates"),
954        doc = "    datetime!(+9999-12-31 23:59:59.999_999_999 +10)"
955    )]
956    /// );
957    ///
958    /// assert_eq!(
959    ///     datetime!(2019-11-25 15:30 +10).saturating_add(27.hours()),
960    ///     datetime!(2019-11-26 18:30 +10)
961    /// );
962    /// ```
963    pub const fn saturating_add(self, duration: Duration) -> Self {
964        if let Some(datetime) = self.checked_add(duration) {
965            datetime
966        } else if duration.is_negative() {
967            PrimitiveDateTime::MIN.assume_offset(self.offset())
968        } else {
969            PrimitiveDateTime::MAX.assume_offset(self.offset())
970        }
971    }
972
973    /// Computes `self - duration`, saturating value on overflow.
974    ///
975    /// ```
976    /// # use time::ext::NumericalDuration;
977    /// # use time_macros::datetime;
978    /// assert_eq!(
979    #[cfg_attr(
980        feature = "large-dates",
981        doc = "    datetime!(-999999-01-01 0:00 +10).saturating_sub(2.days()),"
982    )]
983    #[cfg_attr(feature = "large-dates", doc = "    datetime!(-999999-01-01 0:00 +10)")]
984    #[cfg_attr(
985        not(feature = "large-dates"),
986        doc = "    datetime!(-9999-01-01 0:00 +10).saturating_sub(2.days()),"
987    )]
988    #[cfg_attr(
989        not(feature = "large-dates"),
990        doc = "    datetime!(-9999-01-01 0:00 +10)"
991    )]
992    /// );
993    ///
994    /// assert_eq!(
995    #[cfg_attr(
996        feature = "large-dates",
997        doc = "    datetime!(+999999-12-31 23:59:59.999_999_999 +10).saturating_sub((-2).days()),"
998    )]
999    #[cfg_attr(
1000        feature = "large-dates",
1001        doc = "    datetime!(+999999-12-31 23:59:59.999_999_999 +10)"
1002    )]
1003    #[cfg_attr(
1004        not(feature = "large-dates"),
1005        doc = "    datetime!(+9999-12-31 23:59:59.999_999_999 +10).saturating_sub((-2).days()),"
1006    )]
1007    #[cfg_attr(
1008        not(feature = "large-dates"),
1009        doc = "    datetime!(+9999-12-31 23:59:59.999_999_999 +10)"
1010    )]
1011    /// );
1012    ///
1013    /// assert_eq!(
1014    ///     datetime!(2019-11-25 15:30 +10).saturating_sub(27.hours()),
1015    ///     datetime!(2019-11-24 12:30 +10)
1016    /// );
1017    /// ```
1018    pub const fn saturating_sub(self, duration: Duration) -> Self {
1019        if let Some(datetime) = self.checked_sub(duration) {
1020            datetime
1021        } else if duration.is_negative() {
1022            PrimitiveDateTime::MAX.assume_offset(self.offset())
1023        } else {
1024            PrimitiveDateTime::MIN.assume_offset(self.offset())
1025        }
1026    }
1027}
1028
1029/// Methods that replace part of the `OffsetDateTime`.
1030impl OffsetDateTime {
1031    /// Replace the time, which is assumed to be in the stored offset. The date and offset
1032    /// components are unchanged.
1033    ///
1034    /// ```rust
1035    /// # use time_macros::{datetime, time};
1036    /// assert_eq!(
1037    ///     datetime!(2020-01-01 5:00 UTC).replace_time(time!(12:00)),
1038    ///     datetime!(2020-01-01 12:00 UTC)
1039    /// );
1040    /// assert_eq!(
1041    ///     datetime!(2020-01-01 12:00 -5).replace_time(time!(7:00)),
1042    ///     datetime!(2020-01-01 7:00 -5)
1043    /// );
1044    /// assert_eq!(
1045    ///     datetime!(2020-01-01 0:00 +1).replace_time(time!(12:00)),
1046    ///     datetime!(2020-01-01 12:00 +1)
1047    /// );
1048    /// ```
1049    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1050    pub const fn replace_time(self, time: Time) -> Self {
1051        Self::new_in_offset(self.date(), time, self.offset())
1052    }
1053
1054    /// Replace the date, which is assumed to be in the stored offset. The time and offset
1055    /// components are unchanged.
1056    ///
1057    /// ```rust
1058    /// # use time_macros::{datetime, date};
1059    /// assert_eq!(
1060    ///     datetime!(2020-01-01 12:00 UTC).replace_date(date!(2020-01-30)),
1061    ///     datetime!(2020-01-30 12:00 UTC)
1062    /// );
1063    /// assert_eq!(
1064    ///     datetime!(2020-01-01 0:00 +1).replace_date(date!(2020-01-30)),
1065    ///     datetime!(2020-01-30 0:00 +1)
1066    /// );
1067    /// ```
1068    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1069    pub const fn replace_date(self, date: Date) -> Self {
1070        Self::new_in_offset(date, self.time(), self.offset())
1071    }
1072
1073    /// Replace the date and time, which are assumed to be in the stored offset. The offset
1074    /// component remains unchanged.
1075    ///
1076    /// ```rust
1077    /// # use time_macros::datetime;
1078    /// assert_eq!(
1079    ///     datetime!(2020-01-01 12:00 UTC).replace_date_time(datetime!(2020-01-30 16:00)),
1080    ///     datetime!(2020-01-30 16:00 UTC)
1081    /// );
1082    /// assert_eq!(
1083    ///     datetime!(2020-01-01 12:00 +1).replace_date_time(datetime!(2020-01-30 0:00)),
1084    ///     datetime!(2020-01-30 0:00 +1)
1085    /// );
1086    /// ```
1087    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1088    pub const fn replace_date_time(self, date_time: PrimitiveDateTime) -> Self {
1089        date_time.assume_offset(self.offset())
1090    }
1091
1092    /// Replace the offset. The date and time components remain unchanged.
1093    ///
1094    /// ```rust
1095    /// # use time_macros::{datetime, offset};
1096    /// assert_eq!(
1097    ///     datetime!(2020-01-01 0:00 UTC).replace_offset(offset!(-5)),
1098    ///     datetime!(2020-01-01 0:00 -5)
1099    /// );
1100    /// ```
1101    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1102    pub const fn replace_offset(self, offset: UtcOffset) -> Self {
1103        self.date_time().assume_offset(offset)
1104    }
1105
1106    /// Replace the year. The month and day will be unchanged.
1107    ///
1108    /// ```rust
1109    /// # use time_macros::datetime;
1110    /// assert_eq!(
1111    ///     datetime!(2022-02-18 12:00 +01).replace_year(2019),
1112    ///     Ok(datetime!(2019-02-18 12:00 +01))
1113    /// );
1114    /// 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
1115    /// 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
1116    /// ```
1117    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1118    pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1119        Ok(const_try!(self.date_time().replace_year(year)).assume_offset(self.offset()))
1120    }
1121
1122    /// Replace the month of the year.
1123    ///
1124    /// ```rust
1125    /// # use time_macros::datetime;
1126    /// # use time::Month;
1127    /// assert_eq!(
1128    ///     datetime!(2022-02-18 12:00 +01).replace_month(Month::January),
1129    ///     Ok(datetime!(2022-01-18 12:00 +01))
1130    /// );
1131    /// assert!(datetime!(2022-01-30 12:00 +01).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
1132    /// ```
1133    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1134    pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1135        Ok(const_try!(self.date_time().replace_month(month)).assume_offset(self.offset()))
1136    }
1137
1138    /// Replace the day of the month.
1139    ///
1140    /// ```rust
1141    /// # use time_macros::datetime;
1142    /// assert_eq!(
1143    ///     datetime!(2022-02-18 12:00 +01).replace_day(1),
1144    ///     Ok(datetime!(2022-02-01 12:00 +01))
1145    /// );
1146    /// assert!(datetime!(2022-02-18 12:00 +01).replace_day(0).is_err()); // 00 isn't a valid day
1147    /// assert!(datetime!(2022-02-18 12:00 +01).replace_day(30).is_err()); // 30 isn't a valid day in February
1148    /// ```
1149    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1150    pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1151        Ok(const_try!(self.date_time().replace_day(day)).assume_offset(self.offset()))
1152    }
1153
1154    /// Replace the day of the year.
1155    ///
1156    /// ```rust
1157    /// # use time_macros::datetime;
1158    /// assert_eq!(datetime!(2022-049 12:00 +01).replace_ordinal(1), Ok(datetime!(2022-001 12:00 +01)));
1159    /// assert!(datetime!(2022-049 12:00 +01).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
1160    /// assert!(datetime!(2022-049 12:00 +01).replace_ordinal(366).is_err()); // 2022 isn't a leap year
1161    /// ```
1162    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1163    pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1164        Ok(const_try!(self.date_time().replace_ordinal(ordinal)).assume_offset(self.offset()))
1165    }
1166
1167    /// Replace the clock hour.
1168    ///
1169    /// ```rust
1170    /// # use time_macros::datetime;
1171    /// assert_eq!(
1172    ///     datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_hour(7),
1173    ///     Ok(datetime!(2022-02-18 07:02:03.004_005_006 +01))
1174    /// );
1175    /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_hour(24).is_err()); // 24 isn't a valid hour
1176    /// ```
1177    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1178    pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
1179        Ok(const_try!(self.date_time().replace_hour(hour)).assume_offset(self.offset()))
1180    }
1181
1182    /// Replace the minutes within the hour.
1183    ///
1184    /// ```rust
1185    /// # use time_macros::datetime;
1186    /// assert_eq!(
1187    ///     datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_minute(7),
1188    ///     Ok(datetime!(2022-02-18 01:07:03.004_005_006 +01))
1189    /// );
1190    /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_minute(60).is_err()); // 60 isn't a valid minute
1191    /// ```
1192    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1193    pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
1194        Ok(const_try!(self.date_time().replace_minute(minute)).assume_offset(self.offset()))
1195    }
1196
1197    /// Replace the seconds within the minute.
1198    ///
1199    /// ```rust
1200    /// # use time_macros::datetime;
1201    /// assert_eq!(
1202    ///     datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_second(7),
1203    ///     Ok(datetime!(2022-02-18 01:02:07.004_005_006 +01))
1204    /// );
1205    /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_second(60).is_err()); // 60 isn't a valid second
1206    /// ```
1207    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1208    pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
1209        Ok(const_try!(self.date_time().replace_second(second)).assume_offset(self.offset()))
1210    }
1211
1212    /// Replace the milliseconds within the second.
1213    ///
1214    /// ```rust
1215    /// # use time_macros::datetime;
1216    /// assert_eq!(
1217    ///     datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_millisecond(7),
1218    ///     Ok(datetime!(2022-02-18 01:02:03.007 +01))
1219    /// );
1220    /// 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
1221    /// ```
1222    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1223    pub const fn replace_millisecond(
1224        self,
1225        millisecond: u16,
1226    ) -> Result<Self, error::ComponentRange> {
1227        Ok(
1228            const_try!(self.date_time().replace_millisecond(millisecond))
1229                .assume_offset(self.offset()),
1230        )
1231    }
1232
1233    /// Replace the microseconds within the second.
1234    ///
1235    /// ```rust
1236    /// # use time_macros::datetime;
1237    /// assert_eq!(
1238    ///     datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_microsecond(7_008),
1239    ///     Ok(datetime!(2022-02-18 01:02:03.007_008 +01))
1240    /// );
1241    /// 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
1242    /// ```
1243    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1244    pub const fn replace_microsecond(
1245        self,
1246        microsecond: u32,
1247    ) -> Result<Self, error::ComponentRange> {
1248        Ok(
1249            const_try!(self.date_time().replace_microsecond(microsecond))
1250                .assume_offset(self.offset()),
1251        )
1252    }
1253
1254    /// Replace the nanoseconds within the second.
1255    ///
1256    /// ```rust
1257    /// # use time_macros::datetime;
1258    /// assert_eq!(
1259    ///     datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_nanosecond(7_008_009),
1260    ///     Ok(datetime!(2022-02-18 01:02:03.007_008_009 +01))
1261    /// );
1262    /// 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
1263    /// ```
1264    #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1265    pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1266        Ok(
1267            const_try!(self.date_time().replace_nanosecond(nanosecond))
1268                .assume_offset(self.offset()),
1269        )
1270    }
1271}
1272
1273#[cfg(feature = "formatting")]
1274impl OffsetDateTime {
1275    /// Format the `OffsetDateTime` using the provided [format
1276    /// description](crate::format_description).
1277    pub fn format_into(
1278        self,
1279        output: &mut (impl io::Write + ?Sized),
1280        format: &(impl Formattable + ?Sized),
1281    ) -> Result<usize, error::Format> {
1282        format.format_into(
1283            output,
1284            Some(self.date()),
1285            Some(self.time()),
1286            Some(self.offset()),
1287        )
1288    }
1289
1290    /// Format the `OffsetDateTime` using the provided [format
1291    /// description](crate::format_description).
1292    ///
1293    /// ```rust
1294    /// # use time::format_description;
1295    /// # use time_macros::datetime;
1296    /// let format = format_description::parse(
1297    ///     "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
1298    ///          sign:mandatory]:[offset_minute]:[offset_second]",
1299    /// )?;
1300    /// assert_eq!(
1301    ///     datetime!(2020-01-02 03:04:05 +06:07:08).format(&format)?,
1302    ///     "2020-01-02 03:04:05 +06:07:08"
1303    /// );
1304    /// # Ok::<_, time::Error>(())
1305    /// ```
1306    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1307        format.format(Some(self.date()), Some(self.time()), Some(self.offset()))
1308    }
1309}
1310
1311#[cfg(feature = "parsing")]
1312impl OffsetDateTime {
1313    /// Parse an `OffsetDateTime` from the input using the provided [format
1314    /// description](crate::format_description).
1315    ///
1316    /// ```rust
1317    /// # use time::OffsetDateTime;
1318    /// # use time_macros::{datetime, format_description};
1319    /// let format = format_description!(
1320    ///     "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
1321    ///          sign:mandatory]:[offset_minute]:[offset_second]"
1322    /// );
1323    /// assert_eq!(
1324    ///     OffsetDateTime::parse("2020-01-02 03:04:05 +06:07:08", &format)?,
1325    ///     datetime!(2020-01-02 03:04:05 +06:07:08)
1326    /// );
1327    /// # Ok::<_, time::Error>(())
1328    /// ```
1329    pub fn parse(
1330        input: &str,
1331        description: &(impl Parsable + ?Sized),
1332    ) -> Result<Self, error::Parse> {
1333        description.parse_offset_date_time(input.as_bytes())
1334    }
1335
1336    /// A helper method to check if the `OffsetDateTime` is a valid representation of a leap second.
1337    /// Leap seconds, when parsed, are represented as the preceding nanosecond. However, leap
1338    /// seconds can only occur as the last second of a month UTC.
1339    #[cfg(feature = "parsing")]
1340    pub(crate) const fn is_valid_leap_second_stand_in(self) -> bool {
1341        // This comparison doesn't need to be adjusted for the stored offset, so check it first for
1342        // speed.
1343        if self.nanosecond() != 999_999_999 {
1344            return false;
1345        }
1346
1347        let (year, ordinal, time) = self.to_offset_raw(UtcOffset::UTC);
1348        let Ok(date) = Date::from_ordinal_date(year, ordinal) else {
1349            return false;
1350        };
1351
1352        time.hour() == 23
1353            && time.minute() == 59
1354            && time.second() == 59
1355            && date.day() == date.month().length(year)
1356    }
1357}
1358
1359impl SmartDisplay for OffsetDateTime {
1360    type Metadata = ();
1361
1362    fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
1363        let width =
1364            smart_display::padded_width_of!(self.date(), " ", self.time(), " ", self.offset());
1365        Metadata::new(width, self, ())
1366    }
1367
1368    fn fmt_with_metadata(
1369        &self,
1370        f: &mut fmt::Formatter<'_>,
1371        metadata: Metadata<Self>,
1372    ) -> fmt::Result {
1373        f.pad_with_width(
1374            metadata.unpadded_width(),
1375            format_args!("{} {} {}", self.date(), self.time(), self.offset()),
1376        )
1377    }
1378}
1379
1380impl fmt::Display for OffsetDateTime {
1381    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1382        SmartDisplay::fmt(self, f)
1383    }
1384}
1385
1386impl fmt::Debug for OffsetDateTime {
1387    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1388        fmt::Display::fmt(self, f)
1389    }
1390}
1391
1392impl Add<Duration> for OffsetDateTime {
1393    type Output = Self;
1394
1395    /// # Panics
1396    ///
1397    /// This may panic if an overflow occurs.
1398    fn add(self, duration: Duration) -> Self::Output {
1399        self.checked_add(duration)
1400            .expect("resulting value is out of range")
1401    }
1402}
1403
1404impl Add<StdDuration> for OffsetDateTime {
1405    type Output = Self;
1406
1407    /// # Panics
1408    ///
1409    /// This may panic if an overflow occurs.
1410    fn add(self, duration: StdDuration) -> Self::Output {
1411        let (is_next_day, time) = self.time().adjusting_add_std(duration);
1412
1413        Self::new_in_offset(
1414            if is_next_day {
1415                (self.date() + duration)
1416                    .next_day()
1417                    .expect("resulting value is out of range")
1418            } else {
1419                self.date() + duration
1420            },
1421            time,
1422            self.offset,
1423        )
1424    }
1425}
1426
1427impl AddAssign<Duration> for OffsetDateTime {
1428    /// # Panics
1429    ///
1430    /// This may panic if an overflow occurs.
1431    fn add_assign(&mut self, rhs: Duration) {
1432        *self = *self + rhs;
1433    }
1434}
1435
1436impl AddAssign<StdDuration> for OffsetDateTime {
1437    /// # Panics
1438    ///
1439    /// This may panic if an overflow occurs.
1440    fn add_assign(&mut self, rhs: StdDuration) {
1441        *self = *self + rhs;
1442    }
1443}
1444
1445impl Sub<Duration> for OffsetDateTime {
1446    type Output = Self;
1447
1448    /// # Panics
1449    ///
1450    /// This may panic if an overflow occurs.
1451    fn sub(self, rhs: Duration) -> Self::Output {
1452        self.checked_sub(rhs)
1453            .expect("resulting value is out of range")
1454    }
1455}
1456
1457impl Sub<StdDuration> for OffsetDateTime {
1458    type Output = Self;
1459
1460    /// # Panics
1461    ///
1462    /// This may panic if an overflow occurs.
1463    fn sub(self, duration: StdDuration) -> Self::Output {
1464        let (is_previous_day, time) = self.time().adjusting_sub_std(duration);
1465
1466        Self::new_in_offset(
1467            if is_previous_day {
1468                (self.date() - duration)
1469                    .previous_day()
1470                    .expect("resulting value is out of range")
1471            } else {
1472                self.date() - duration
1473            },
1474            time,
1475            self.offset,
1476        )
1477    }
1478}
1479
1480impl SubAssign<Duration> for OffsetDateTime {
1481    /// # Panics
1482    ///
1483    /// This may panic if an overflow occurs.
1484    fn sub_assign(&mut self, rhs: Duration) {
1485        *self = *self - rhs;
1486    }
1487}
1488
1489impl SubAssign<StdDuration> for OffsetDateTime {
1490    /// # Panics
1491    ///
1492    /// This may panic if an overflow occurs.
1493    fn sub_assign(&mut self, rhs: StdDuration) {
1494        *self = *self - rhs;
1495    }
1496}
1497
1498impl Sub for OffsetDateTime {
1499    type Output = Duration;
1500
1501    /// # Panics
1502    ///
1503    /// This may panic if an overflow occurs.
1504    fn sub(self, rhs: Self) -> Self::Output {
1505        let base = self.date_time() - rhs.date_time();
1506        let adjustment = Duration::seconds(
1507            (self.offset.whole_seconds() - rhs.offset.whole_seconds()).extend::<i64>(),
1508        );
1509        base - adjustment
1510    }
1511}