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