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