time/
offset_date_time.rs

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