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