[go: up one dir, main page]

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