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