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