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