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, Duration, Month, PrimitiveDateTime, 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 [`PrimitiveDateTime`] with a [`UtcOffset`].
37#[derive(Clone, Copy, Eq)]
38pub struct OffsetDateTime {
39 local_date_time: PrimitiveDateTime,
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 PrimitiveDateTime::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::PrimitiveDateTime;
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 /// PrimitiveDateTime::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::{Duration, OffsetDateTime, ext::NumericalDuration};
430 /// let (timestamp, nanos) = (1, 500_000_000);
431 /// assert_eq!(
432 /// OffsetDateTime::from_unix_timestamp(timestamp)? + Duration::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 datetime = const_try!(Self::from_unix_timestamp(div_floor!(
491 timestamp,
492 Nanosecond::per_t::<i128>(Second)
493 ) as i64));
494
495 Ok(Self::new_in_offset(
496 datetime.date(),
497 // Safety: `nanosecond` is in range due to `rem_euclid`.
498 unsafe {
499 Time::__from_hms_nanos_unchecked(
500 datetime.hour(),
501 datetime.minute(),
502 datetime.second(),
503 timestamp.rem_euclid(Nanosecond::per_t(Second)) as u32,
504 )
505 },
506 UtcOffset::UTC,
507 ))
508 }
509
510 /// Get the [`UtcOffset`].
511 ///
512 /// ```rust
513 /// # use time_macros::{datetime, offset};
514 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).offset(), offset!(UTC));
515 /// assert_eq!(datetime!(2019-01-01 0:00 +1).offset(), offset!(+1));
516 /// ```
517 #[inline]
518 pub const fn offset(self) -> UtcOffset {
519 self.offset
520 }
521
522 /// Get the [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
523 ///
524 /// ```rust
525 /// # use time_macros::datetime;
526 /// assert_eq!(datetime!(1970-01-01 0:00 UTC).unix_timestamp(), 0);
527 /// assert_eq!(datetime!(1970-01-01 0:00 -1).unix_timestamp(), 3_600);
528 /// ```
529 #[inline]
530 pub const fn unix_timestamp(self) -> i64 {
531 let days = (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64)
532 * Second::per_t::<i64>(Day);
533 let hours = self.hour() as i64 * Second::per_t::<i64>(Hour);
534 let minutes = self.minute() as i64 * Second::per_t::<i64>(Minute);
535 let seconds = self.second() as i64;
536 let offset_seconds = self.offset.whole_seconds() as i64;
537 days + hours + minutes + seconds - offset_seconds
538 }
539
540 /// Get the Unix timestamp in nanoseconds.
541 ///
542 /// ```rust
543 /// use time_macros::datetime;
544 /// assert_eq!(datetime!(1970-01-01 0:00 UTC).unix_timestamp_nanos(), 0);
545 /// assert_eq!(
546 /// datetime!(1970-01-01 0:00 -1).unix_timestamp_nanos(),
547 /// 3_600_000_000_000,
548 /// );
549 /// ```
550 #[inline]
551 pub const fn unix_timestamp_nanos(self) -> i128 {
552 self.unix_timestamp() as i128 * Nanosecond::per_t::<i128>(Second)
553 + self.nanosecond() as i128
554 }
555
556 /// Get the [`PrimitiveDateTime`] in the stored offset.
557 #[inline]
558 pub(crate) const fn date_time(self) -> PrimitiveDateTime {
559 self.local_date_time
560 }
561
562 /// Get the [`Date`] in the stored offset.
563 ///
564 /// ```rust
565 /// # use time_macros::{date, datetime, offset};
566 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).date(), date!(2019-01-01));
567 /// assert_eq!(
568 /// datetime!(2019-01-01 0:00 UTC)
569 /// .to_offset(offset!(-1))
570 /// .date(),
571 /// date!(2018-12-31),
572 /// );
573 /// ```
574 #[inline]
575 pub const fn date(self) -> Date {
576 self.date_time().date()
577 }
578
579 /// Get the [`Time`] in the stored offset.
580 ///
581 /// ```rust
582 /// # use time_macros::{datetime, offset, time};
583 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).time(), time!(0:00));
584 /// assert_eq!(
585 /// datetime!(2019-01-01 0:00 UTC)
586 /// .to_offset(offset!(-1))
587 /// .time(),
588 /// time!(23:00)
589 /// );
590 /// ```
591 #[inline]
592 pub const fn time(self) -> Time {
593 self.date_time().time()
594 }
595
596 /// Get the year of the date in the stored offset.
597 ///
598 /// ```rust
599 /// # use time_macros::{datetime, offset};
600 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).year(), 2019);
601 /// assert_eq!(
602 /// datetime!(2019-12-31 23:00 UTC)
603 /// .to_offset(offset!(+1))
604 /// .year(),
605 /// 2020,
606 /// );
607 /// assert_eq!(datetime!(2020-01-01 0:00 UTC).year(), 2020);
608 /// ```
609 #[inline]
610 pub const fn year(self) -> i32 {
611 self.date().year()
612 }
613
614 /// Get the month of the date in the stored offset.
615 ///
616 /// ```rust
617 /// # use time::Month;
618 /// # use time_macros::{datetime, offset};
619 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).month(), Month::January);
620 /// assert_eq!(
621 /// datetime!(2019-12-31 23:00 UTC)
622 /// .to_offset(offset!(+1))
623 /// .month(),
624 /// Month::January,
625 /// );
626 /// ```
627 #[inline]
628 pub const fn month(self) -> Month {
629 self.date().month()
630 }
631
632 /// Get the day of the date in the stored offset.
633 ///
634 /// The returned value will always be in the range `1..=31`.
635 ///
636 /// ```rust
637 /// # use time_macros::{datetime, offset};
638 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).day(), 1);
639 /// assert_eq!(
640 /// datetime!(2019-12-31 23:00 UTC)
641 /// .to_offset(offset!(+1))
642 /// .day(),
643 /// 1,
644 /// );
645 /// ```
646 #[inline]
647 pub const fn day(self) -> u8 {
648 self.date().day()
649 }
650
651 /// Get the day of the year of the date in the stored offset.
652 ///
653 /// The returned value will always be in the range `1..=366`.
654 ///
655 /// ```rust
656 /// # use time_macros::{datetime, offset};
657 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).ordinal(), 1);
658 /// assert_eq!(
659 /// datetime!(2019-12-31 23:00 UTC)
660 /// .to_offset(offset!(+1))
661 /// .ordinal(),
662 /// 1,
663 /// );
664 /// ```
665 #[inline]
666 pub const fn ordinal(self) -> u16 {
667 self.date().ordinal()
668 }
669
670 /// Get the ISO week number of the date in the stored offset.
671 ///
672 /// The returned value will always be in the range `1..=53`.
673 ///
674 /// ```rust
675 /// # use time_macros::datetime;
676 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).iso_week(), 1);
677 /// assert_eq!(datetime!(2020-01-01 0:00 UTC).iso_week(), 1);
678 /// assert_eq!(datetime!(2020-12-31 0:00 UTC).iso_week(), 53);
679 /// assert_eq!(datetime!(2021-01-01 0:00 UTC).iso_week(), 53);
680 /// ```
681 #[inline]
682 pub const fn iso_week(self) -> u8 {
683 self.date().iso_week()
684 }
685
686 /// Get the week number where week 1 begins on the first Sunday.
687 ///
688 /// The returned value will always be in the range `0..=53`.
689 ///
690 /// ```rust
691 /// # use time_macros::datetime;
692 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).sunday_based_week(), 0);
693 /// assert_eq!(datetime!(2020-01-01 0:00 UTC).sunday_based_week(), 0);
694 /// assert_eq!(datetime!(2020-12-31 0:00 UTC).sunday_based_week(), 52);
695 /// assert_eq!(datetime!(2021-01-01 0:00 UTC).sunday_based_week(), 0);
696 /// ```
697 #[inline]
698 pub const fn sunday_based_week(self) -> u8 {
699 self.date().sunday_based_week()
700 }
701
702 /// Get the week number where week 1 begins on the first Monday.
703 ///
704 /// The returned value will always be in the range `0..=53`.
705 ///
706 /// ```rust
707 /// # use time_macros::datetime;
708 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).monday_based_week(), 0);
709 /// assert_eq!(datetime!(2020-01-01 0:00 UTC).monday_based_week(), 0);
710 /// assert_eq!(datetime!(2020-12-31 0:00 UTC).monday_based_week(), 52);
711 /// assert_eq!(datetime!(2021-01-01 0:00 UTC).monday_based_week(), 0);
712 /// ```
713 #[inline]
714 pub const fn monday_based_week(self) -> u8 {
715 self.date().monday_based_week()
716 }
717
718 /// Get the year, month, and day.
719 ///
720 /// ```rust
721 /// # use time::Month;
722 /// # use time_macros::datetime;
723 /// assert_eq!(
724 /// datetime!(2019-01-01 0:00 UTC).to_calendar_date(),
725 /// (2019, Month::January, 1)
726 /// );
727 /// ```
728 #[inline]
729 pub const fn to_calendar_date(self) -> (i32, Month, u8) {
730 self.date().to_calendar_date()
731 }
732
733 /// Get the year and ordinal day number.
734 ///
735 /// ```rust
736 /// # use time_macros::datetime;
737 /// assert_eq!(
738 /// datetime!(2019-01-01 0:00 UTC).to_ordinal_date(),
739 /// (2019, 1)
740 /// );
741 /// ```
742 #[inline]
743 pub const fn to_ordinal_date(self) -> (i32, u16) {
744 self.date().to_ordinal_date()
745 }
746
747 /// Get the ISO 8601 year, week number, and weekday.
748 ///
749 /// ```rust
750 /// # use time::Weekday::*;
751 /// # use time_macros::datetime;
752 /// assert_eq!(
753 /// datetime!(2019-01-01 0:00 UTC).to_iso_week_date(),
754 /// (2019, 1, Tuesday)
755 /// );
756 /// assert_eq!(
757 /// datetime!(2019-10-04 0:00 UTC).to_iso_week_date(),
758 /// (2019, 40, Friday)
759 /// );
760 /// assert_eq!(
761 /// datetime!(2020-01-01 0:00 UTC).to_iso_week_date(),
762 /// (2020, 1, Wednesday)
763 /// );
764 /// assert_eq!(
765 /// datetime!(2020-12-31 0:00 UTC).to_iso_week_date(),
766 /// (2020, 53, Thursday)
767 /// );
768 /// assert_eq!(
769 /// datetime!(2021-01-01 0:00 UTC).to_iso_week_date(),
770 /// (2020, 53, Friday)
771 /// );
772 /// ```
773 #[inline]
774 pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
775 self.date().to_iso_week_date()
776 }
777
778 /// Get the weekday of the date in the stored offset.
779 ///
780 /// ```rust
781 /// # use time::Weekday::*;
782 /// # use time_macros::datetime;
783 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).weekday(), Tuesday);
784 /// assert_eq!(datetime!(2019-02-01 0:00 UTC).weekday(), Friday);
785 /// assert_eq!(datetime!(2019-03-01 0:00 UTC).weekday(), Friday);
786 /// ```
787 #[inline]
788 pub const fn weekday(self) -> Weekday {
789 self.date().weekday()
790 }
791
792 /// Get the Julian day for the date. The time is not taken into account for this calculation.
793 ///
794 /// ```rust
795 /// # use time_macros::datetime;
796 /// assert_eq!(datetime!(-4713-11-24 0:00 UTC).to_julian_day(), 0);
797 /// assert_eq!(datetime!(2000-01-01 0:00 UTC).to_julian_day(), 2_451_545);
798 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).to_julian_day(), 2_458_485);
799 /// assert_eq!(datetime!(2019-12-31 0:00 UTC).to_julian_day(), 2_458_849);
800 /// ```
801 #[inline]
802 pub const fn to_julian_day(self) -> i32 {
803 self.date().to_julian_day()
804 }
805
806 /// Get the clock hour, minute, and second.
807 ///
808 /// ```rust
809 /// # use time_macros::datetime;
810 /// assert_eq!(datetime!(2020-01-01 0:00:00 UTC).to_hms(), (0, 0, 0));
811 /// assert_eq!(datetime!(2020-01-01 23:59:59 UTC).to_hms(), (23, 59, 59));
812 /// ```
813 #[inline]
814 pub const fn to_hms(self) -> (u8, u8, u8) {
815 self.time().as_hms()
816 }
817
818 /// Get the clock hour, minute, second, and millisecond.
819 ///
820 /// ```rust
821 /// # use time_macros::datetime;
822 /// assert_eq!(
823 /// datetime!(2020-01-01 0:00:00 UTC).to_hms_milli(),
824 /// (0, 0, 0, 0)
825 /// );
826 /// assert_eq!(
827 /// datetime!(2020-01-01 23:59:59.999 UTC).to_hms_milli(),
828 /// (23, 59, 59, 999)
829 /// );
830 /// ```
831 #[inline]
832 pub const fn to_hms_milli(self) -> (u8, u8, u8, u16) {
833 self.time().as_hms_milli()
834 }
835
836 /// Get the clock hour, minute, second, and microsecond.
837 ///
838 /// ```rust
839 /// # use time_macros::datetime;
840 /// assert_eq!(
841 /// datetime!(2020-01-01 0:00:00 UTC).to_hms_micro(),
842 /// (0, 0, 0, 0)
843 /// );
844 /// assert_eq!(
845 /// datetime!(2020-01-01 23:59:59.999_999 UTC).to_hms_micro(),
846 /// (23, 59, 59, 999_999)
847 /// );
848 /// ```
849 #[inline]
850 pub const fn to_hms_micro(self) -> (u8, u8, u8, u32) {
851 self.time().as_hms_micro()
852 }
853
854 /// Get the clock hour, minute, second, and nanosecond.
855 ///
856 /// ```rust
857 /// # use time_macros::datetime;
858 /// assert_eq!(
859 /// datetime!(2020-01-01 0:00:00 UTC).to_hms_nano(),
860 /// (0, 0, 0, 0)
861 /// );
862 /// assert_eq!(
863 /// datetime!(2020-01-01 23:59:59.999_999_999 UTC).to_hms_nano(),
864 /// (23, 59, 59, 999_999_999)
865 /// );
866 /// ```
867 #[inline]
868 pub const fn to_hms_nano(self) -> (u8, u8, u8, u32) {
869 self.time().as_hms_nano()
870 }
871
872 /// Get the clock hour in the stored offset.
873 ///
874 /// The returned value will always be in the range `0..24`.
875 ///
876 /// ```rust
877 /// # use time_macros::{datetime, offset};
878 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).hour(), 0);
879 /// assert_eq!(
880 /// datetime!(2019-01-01 23:59:59 UTC)
881 /// .to_offset(offset!(-2))
882 /// .hour(),
883 /// 21,
884 /// );
885 /// ```
886 #[inline]
887 pub const fn hour(self) -> u8 {
888 self.time().hour()
889 }
890
891 /// Get the minute within the hour in the stored offset.
892 ///
893 /// The returned value will always be in the range `0..60`.
894 ///
895 /// ```rust
896 /// # use time_macros::{datetime, offset};
897 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).minute(), 0);
898 /// assert_eq!(
899 /// datetime!(2019-01-01 23:59:59 UTC)
900 /// .to_offset(offset!(+0:30))
901 /// .minute(),
902 /// 29,
903 /// );
904 /// ```
905 #[inline]
906 pub const fn minute(self) -> u8 {
907 self.time().minute()
908 }
909
910 /// Get the second within the minute in the stored offset.
911 ///
912 /// The returned value will always be in the range `0..60`.
913 ///
914 /// ```rust
915 /// # use time_macros::{datetime, offset};
916 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).second(), 0);
917 /// assert_eq!(
918 /// datetime!(2019-01-01 23:59:59 UTC)
919 /// .to_offset(offset!(+0:00:30))
920 /// .second(),
921 /// 29,
922 /// );
923 /// ```
924 #[inline]
925 pub const fn second(self) -> u8 {
926 self.time().second()
927 }
928
929 // Because a `UtcOffset` is limited in resolution to one second, any subsecond value will not
930 // change when adjusting for the offset.
931
932 /// Get the milliseconds within the second in the stored offset.
933 ///
934 /// The returned value will always be in the range `0..1_000`.
935 ///
936 /// ```rust
937 /// # use time_macros::datetime;
938 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).millisecond(), 0);
939 /// assert_eq!(datetime!(2019-01-01 23:59:59.999 UTC).millisecond(), 999);
940 /// ```
941 #[inline]
942 pub const fn millisecond(self) -> u16 {
943 self.time().millisecond()
944 }
945
946 /// Get the microseconds within the second in the stored offset.
947 ///
948 /// The returned value will always be in the range `0..1_000_000`.
949 ///
950 /// ```rust
951 /// # use time_macros::datetime;
952 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).microsecond(), 0);
953 /// assert_eq!(
954 /// datetime!(2019-01-01 23:59:59.999_999 UTC).microsecond(),
955 /// 999_999,
956 /// );
957 /// ```
958 #[inline]
959 pub const fn microsecond(self) -> u32 {
960 self.time().microsecond()
961 }
962
963 /// Get the nanoseconds within the second in the stored offset.
964 ///
965 /// The returned value will always be in the range `0..1_000_000_000`.
966 ///
967 /// ```rust
968 /// # use time_macros::datetime;
969 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).nanosecond(), 0);
970 /// assert_eq!(
971 /// datetime!(2019-01-01 23:59:59.999_999_999 UTC).nanosecond(),
972 /// 999_999_999,
973 /// );
974 /// ```
975 #[inline]
976 pub const fn nanosecond(self) -> u32 {
977 self.time().nanosecond()
978 }
979
980 /// Computes `self + duration`, returning `None` if an overflow occurred.
981 ///
982 /// ```
983 /// # use time::{Date, ext::NumericalDuration};
984 /// # use time_macros::{datetime, offset};
985 /// let datetime = Date::MIN.midnight().assume_offset(offset!(+10));
986 /// assert_eq!(datetime.checked_add((-2).days()), None);
987 ///
988 /// let datetime = Date::MAX.midnight().assume_offset(offset!(+10));
989 /// assert_eq!(datetime.checked_add(2.days()), None);
990 ///
991 /// assert_eq!(
992 /// datetime!(2019-11-25 15:30 +10).checked_add(27.hours()),
993 /// Some(datetime!(2019-11-26 18:30 +10))
994 /// );
995 /// ```
996 #[inline]
997 pub const fn checked_add(self, duration: Duration) -> Option<Self> {
998 Some(const_try_opt!(self.date_time().checked_add(duration)).assume_offset(self.offset()))
999 }
1000
1001 /// Computes `self - duration`, returning `None` if an overflow occurred.
1002 ///
1003 /// ```
1004 /// # use time::{Date, ext::NumericalDuration};
1005 /// # use time_macros::{datetime, offset};
1006 /// let datetime = Date::MIN.midnight().assume_offset(offset!(+10));
1007 /// assert_eq!(datetime.checked_sub(2.days()), None);
1008 ///
1009 /// let datetime = Date::MAX.midnight().assume_offset(offset!(+10));
1010 /// assert_eq!(datetime.checked_sub((-2).days()), None);
1011 ///
1012 /// assert_eq!(
1013 /// datetime!(2019-11-25 15:30 +10).checked_sub(27.hours()),
1014 /// Some(datetime!(2019-11-24 12:30 +10))
1015 /// );
1016 /// ```
1017 #[inline]
1018 pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
1019 Some(const_try_opt!(self.date_time().checked_sub(duration)).assume_offset(self.offset()))
1020 }
1021
1022 /// Computes `self + duration`, saturating value on overflow.
1023 ///
1024 /// ```
1025 /// # use time::ext::NumericalDuration;
1026 /// # use time_macros::datetime;
1027 /// assert_eq!(
1028 #[cfg_attr(
1029 feature = "large-dates",
1030 doc = " datetime!(-999999-01-01 0:00 +10).saturating_add((-2).days()),"
1031 )]
1032 #[cfg_attr(feature = "large-dates", doc = " datetime!(-999999-01-01 0:00 +10)")]
1033 #[cfg_attr(
1034 not(feature = "large-dates"),
1035 doc = " datetime!(-9999-01-01 0:00 +10).saturating_add((-2).days()),"
1036 )]
1037 #[cfg_attr(
1038 not(feature = "large-dates"),
1039 doc = " datetime!(-9999-01-01 0:00 +10)"
1040 )]
1041 /// );
1042 ///
1043 /// assert_eq!(
1044 #[cfg_attr(
1045 feature = "large-dates",
1046 doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10).saturating_add(2.days()),"
1047 )]
1048 #[cfg_attr(
1049 feature = "large-dates",
1050 doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10)"
1051 )]
1052 #[cfg_attr(
1053 not(feature = "large-dates"),
1054 doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10).saturating_add(2.days()),"
1055 )]
1056 #[cfg_attr(
1057 not(feature = "large-dates"),
1058 doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10)"
1059 )]
1060 /// );
1061 ///
1062 /// assert_eq!(
1063 /// datetime!(2019-11-25 15:30 +10).saturating_add(27.hours()),
1064 /// datetime!(2019-11-26 18:30 +10)
1065 /// );
1066 /// ```
1067 #[inline]
1068 pub const fn saturating_add(self, duration: Duration) -> Self {
1069 if let Some(datetime) = self.checked_add(duration) {
1070 datetime
1071 } else if duration.is_negative() {
1072 PrimitiveDateTime::MIN.assume_offset(self.offset())
1073 } else {
1074 PrimitiveDateTime::MAX.assume_offset(self.offset())
1075 }
1076 }
1077
1078 /// Computes `self - duration`, saturating value on overflow.
1079 ///
1080 /// ```
1081 /// # use time::ext::NumericalDuration;
1082 /// # use time_macros::datetime;
1083 /// assert_eq!(
1084 #[cfg_attr(
1085 feature = "large-dates",
1086 doc = " datetime!(-999999-01-01 0:00 +10).saturating_sub(2.days()),"
1087 )]
1088 #[cfg_attr(feature = "large-dates", doc = " datetime!(-999999-01-01 0:00 +10)")]
1089 #[cfg_attr(
1090 not(feature = "large-dates"),
1091 doc = " datetime!(-9999-01-01 0:00 +10).saturating_sub(2.days()),"
1092 )]
1093 #[cfg_attr(
1094 not(feature = "large-dates"),
1095 doc = " datetime!(-9999-01-01 0:00 +10)"
1096 )]
1097 /// );
1098 ///
1099 /// assert_eq!(
1100 #[cfg_attr(
1101 feature = "large-dates",
1102 doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10).saturating_sub((-2).days()),"
1103 )]
1104 #[cfg_attr(
1105 feature = "large-dates",
1106 doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10)"
1107 )]
1108 #[cfg_attr(
1109 not(feature = "large-dates"),
1110 doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10).saturating_sub((-2).days()),"
1111 )]
1112 #[cfg_attr(
1113 not(feature = "large-dates"),
1114 doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10)"
1115 )]
1116 /// );
1117 ///
1118 /// assert_eq!(
1119 /// datetime!(2019-11-25 15:30 +10).saturating_sub(27.hours()),
1120 /// datetime!(2019-11-24 12:30 +10)
1121 /// );
1122 /// ```
1123 #[inline]
1124 pub const fn saturating_sub(self, duration: Duration) -> Self {
1125 if let Some(datetime) = self.checked_sub(duration) {
1126 datetime
1127 } else if duration.is_negative() {
1128 PrimitiveDateTime::MAX.assume_offset(self.offset())
1129 } else {
1130 PrimitiveDateTime::MIN.assume_offset(self.offset())
1131 }
1132 }
1133}
1134
1135/// Methods that replace part of the `OffsetDateTime`.
1136impl OffsetDateTime {
1137 /// Replace the time, which is assumed to be in the stored offset. The date and offset
1138 /// components are unchanged.
1139 ///
1140 /// ```rust
1141 /// # use time_macros::{datetime, time};
1142 /// assert_eq!(
1143 /// datetime!(2020-01-01 5:00 UTC).replace_time(time!(12:00)),
1144 /// datetime!(2020-01-01 12:00 UTC)
1145 /// );
1146 /// assert_eq!(
1147 /// datetime!(2020-01-01 12:00 -5).replace_time(time!(7:00)),
1148 /// datetime!(2020-01-01 7:00 -5)
1149 /// );
1150 /// assert_eq!(
1151 /// datetime!(2020-01-01 0:00 +1).replace_time(time!(12:00)),
1152 /// datetime!(2020-01-01 12:00 +1)
1153 /// );
1154 /// ```
1155 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1156 #[inline]
1157 pub const fn replace_time(self, time: Time) -> Self {
1158 Self::new_in_offset(self.date(), time, self.offset())
1159 }
1160
1161 /// Replace the date, which is assumed to be in the stored offset. The time and offset
1162 /// components are unchanged.
1163 ///
1164 /// ```rust
1165 /// # use time_macros::{datetime, date};
1166 /// assert_eq!(
1167 /// datetime!(2020-01-01 12:00 UTC).replace_date(date!(2020-01-30)),
1168 /// datetime!(2020-01-30 12:00 UTC)
1169 /// );
1170 /// assert_eq!(
1171 /// datetime!(2020-01-01 0:00 +1).replace_date(date!(2020-01-30)),
1172 /// datetime!(2020-01-30 0:00 +1)
1173 /// );
1174 /// ```
1175 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1176 #[inline]
1177 pub const fn replace_date(self, date: Date) -> Self {
1178 Self::new_in_offset(date, self.time(), self.offset())
1179 }
1180
1181 /// Replace the date and time, which are assumed to be in the stored offset. The offset
1182 /// component remains unchanged.
1183 ///
1184 /// ```rust
1185 /// # use time_macros::datetime;
1186 /// assert_eq!(
1187 /// datetime!(2020-01-01 12:00 UTC).replace_date_time(datetime!(2020-01-30 16:00)),
1188 /// datetime!(2020-01-30 16:00 UTC)
1189 /// );
1190 /// assert_eq!(
1191 /// datetime!(2020-01-01 12:00 +1).replace_date_time(datetime!(2020-01-30 0:00)),
1192 /// datetime!(2020-01-30 0:00 +1)
1193 /// );
1194 /// ```
1195 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1196 #[inline]
1197 pub const fn replace_date_time(self, date_time: PrimitiveDateTime) -> Self {
1198 date_time.assume_offset(self.offset())
1199 }
1200
1201 /// Replace the offset. The date and time components remain unchanged.
1202 ///
1203 /// ```rust
1204 /// # use time_macros::{datetime, offset};
1205 /// assert_eq!(
1206 /// datetime!(2020-01-01 0:00 UTC).replace_offset(offset!(-5)),
1207 /// datetime!(2020-01-01 0:00 -5)
1208 /// );
1209 /// ```
1210 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1211 #[inline]
1212 pub const fn replace_offset(self, offset: UtcOffset) -> Self {
1213 self.date_time().assume_offset(offset)
1214 }
1215
1216 /// Replace the year. The month and day will be unchanged.
1217 ///
1218 /// ```rust
1219 /// # use time_macros::datetime;
1220 /// assert_eq!(
1221 /// datetime!(2022-02-18 12:00 +01).replace_year(2019),
1222 /// Ok(datetime!(2019-02-18 12:00 +01))
1223 /// );
1224 /// 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
1225 /// 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
1226 /// ```
1227 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1228 #[inline]
1229 pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1230 Ok(const_try!(self.date_time().replace_year(year)).assume_offset(self.offset()))
1231 }
1232
1233 /// Replace the month of the year.
1234 ///
1235 /// ```rust
1236 /// # use time_macros::datetime;
1237 /// # use time::Month;
1238 /// assert_eq!(
1239 /// datetime!(2022-02-18 12:00 +01).replace_month(Month::January),
1240 /// Ok(datetime!(2022-01-18 12:00 +01))
1241 /// );
1242 /// assert!(datetime!(2022-01-30 12:00 +01).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
1243 /// ```
1244 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1245 #[inline]
1246 pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1247 Ok(const_try!(self.date_time().replace_month(month)).assume_offset(self.offset()))
1248 }
1249
1250 /// Replace the day of the month.
1251 ///
1252 /// ```rust
1253 /// # use time_macros::datetime;
1254 /// assert_eq!(
1255 /// datetime!(2022-02-18 12:00 +01).replace_day(1),
1256 /// Ok(datetime!(2022-02-01 12:00 +01))
1257 /// );
1258 /// assert!(datetime!(2022-02-18 12:00 +01).replace_day(0).is_err()); // 00 isn't a valid day
1259 /// assert!(datetime!(2022-02-18 12:00 +01).replace_day(30).is_err()); // 30 isn't a valid day in February
1260 /// ```
1261 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1262 #[inline]
1263 pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1264 Ok(const_try!(self.date_time().replace_day(day)).assume_offset(self.offset()))
1265 }
1266
1267 /// Replace the day of the year.
1268 ///
1269 /// ```rust
1270 /// # use time_macros::datetime;
1271 /// assert_eq!(datetime!(2022-049 12:00 +01).replace_ordinal(1), Ok(datetime!(2022-001 12:00 +01)));
1272 /// assert!(datetime!(2022-049 12:00 +01).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
1273 /// assert!(datetime!(2022-049 12:00 +01).replace_ordinal(366).is_err()); // 2022 isn't a leap year
1274 /// ```
1275 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1276 #[inline]
1277 pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1278 Ok(const_try!(self.date_time().replace_ordinal(ordinal)).assume_offset(self.offset()))
1279 }
1280
1281 /// Truncate to the start of the day, setting the time to midnight.
1282 ///
1283 /// ```rust
1284 /// # use time_macros::datetime;
1285 /// assert_eq!(
1286 /// datetime!(2022-02-18 15:30:45.123 +01).truncate_to_day(),
1287 /// datetime!(2022-02-18 0:00 +01)
1288 /// );
1289 /// ```
1290 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1291 #[inline]
1292 pub const fn truncate_to_day(mut self) -> Self {
1293 self.local_date_time = self.local_date_time.truncate_to_day();
1294 self
1295 }
1296
1297 /// Replace the clock hour.
1298 ///
1299 /// ```rust
1300 /// # use time_macros::datetime;
1301 /// assert_eq!(
1302 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_hour(7),
1303 /// Ok(datetime!(2022-02-18 07:02:03.004_005_006 +01))
1304 /// );
1305 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_hour(24).is_err()); // 24 isn't a valid hour
1306 /// ```
1307 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1308 #[inline]
1309 pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
1310 Ok(const_try!(self.date_time().replace_hour(hour)).assume_offset(self.offset()))
1311 }
1312
1313 /// Truncate to the hour, setting the minute, second, and subsecond components to zero.
1314 ///
1315 /// ```rust
1316 /// # use time_macros::datetime;
1317 /// assert_eq!(
1318 /// datetime!(2022-02-18 15:30:45.123 +01).truncate_to_hour(),
1319 /// datetime!(2022-02-18 15:00 +01)
1320 /// );
1321 /// ```
1322 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1323 #[inline]
1324 pub const fn truncate_to_hour(mut self) -> Self {
1325 self.local_date_time = self.local_date_time.truncate_to_hour();
1326 self
1327 }
1328
1329 /// Replace the minutes within the hour.
1330 ///
1331 /// ```rust
1332 /// # use time_macros::datetime;
1333 /// assert_eq!(
1334 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_minute(7),
1335 /// Ok(datetime!(2022-02-18 01:07:03.004_005_006 +01))
1336 /// );
1337 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_minute(60).is_err()); // 60 isn't a valid minute
1338 /// ```
1339 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1340 #[inline]
1341 pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
1342 Ok(const_try!(self.date_time().replace_minute(minute)).assume_offset(self.offset()))
1343 }
1344
1345 /// Truncate to the minute, setting the second and subsecond components to zero.
1346 ///
1347 /// ```rust
1348 /// # use time_macros::datetime;
1349 /// assert_eq!(
1350 /// datetime!(2022-02-18 15:30:45.123 +01).truncate_to_minute(),
1351 /// datetime!(2022-02-18 15:30 +01)
1352 /// );
1353 /// ```
1354 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1355 #[inline]
1356 pub const fn truncate_to_minute(mut self) -> Self {
1357 self.local_date_time = self.local_date_time.truncate_to_minute();
1358 self
1359 }
1360
1361 /// Replace the seconds within the minute.
1362 ///
1363 /// ```rust
1364 /// # use time_macros::datetime;
1365 /// assert_eq!(
1366 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_second(7),
1367 /// Ok(datetime!(2022-02-18 01:02:07.004_005_006 +01))
1368 /// );
1369 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_second(60).is_err()); // 60 isn't a valid second
1370 /// ```
1371 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1372 #[inline]
1373 pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
1374 Ok(const_try!(self.date_time().replace_second(second)).assume_offset(self.offset()))
1375 }
1376
1377 /// Truncate to the second, setting the subsecond components to zero.
1378 ///
1379 /// ```rust
1380 /// # use time_macros::datetime;
1381 /// assert_eq!(
1382 /// datetime!(2022-02-18 15:30:45.123 +01).truncate_to_second(),
1383 /// datetime!(2022-02-18 15:30:45 +01)
1384 /// );
1385 /// ```
1386 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1387 #[inline]
1388 pub const fn truncate_to_second(mut self) -> Self {
1389 self.local_date_time = self.local_date_time.truncate_to_second();
1390 self
1391 }
1392
1393 /// Replace the milliseconds within the second.
1394 ///
1395 /// ```rust
1396 /// # use time_macros::datetime;
1397 /// assert_eq!(
1398 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_millisecond(7),
1399 /// Ok(datetime!(2022-02-18 01:02:03.007 +01))
1400 /// );
1401 /// 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
1402 /// ```
1403 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1404 #[inline]
1405 pub const fn replace_millisecond(
1406 self,
1407 millisecond: u16,
1408 ) -> Result<Self, error::ComponentRange> {
1409 Ok(
1410 const_try!(self.date_time().replace_millisecond(millisecond))
1411 .assume_offset(self.offset()),
1412 )
1413 }
1414
1415 /// Truncate to the millisecond, setting the microsecond and nanosecond components to zero.
1416 ///
1417 /// ```rust
1418 /// # use time_macros::datetime;
1419 /// assert_eq!(
1420 /// datetime!(2022-02-18 15:30:45.123_456_789 +01).truncate_to_millisecond(),
1421 /// datetime!(2022-02-18 15:30:45.123 +01)
1422 /// );
1423 /// ```
1424 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1425 #[inline]
1426 pub const fn truncate_to_millisecond(mut self) -> Self {
1427 self.local_date_time = self.local_date_time.truncate_to_millisecond();
1428 self
1429 }
1430
1431 /// Replace the microseconds within the second.
1432 ///
1433 /// ```rust
1434 /// # use time_macros::datetime;
1435 /// assert_eq!(
1436 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_microsecond(7_008),
1437 /// Ok(datetime!(2022-02-18 01:02:03.007_008 +01))
1438 /// );
1439 /// 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
1440 /// ```
1441 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1442 #[inline]
1443 pub const fn replace_microsecond(
1444 self,
1445 microsecond: u32,
1446 ) -> Result<Self, error::ComponentRange> {
1447 Ok(
1448 const_try!(self.date_time().replace_microsecond(microsecond))
1449 .assume_offset(self.offset()),
1450 )
1451 }
1452
1453 /// Truncate to the microsecond, setting the nanosecond component to zero.
1454 ///
1455 /// ```rust
1456 /// # use time_macros::datetime;
1457 /// assert_eq!(
1458 /// datetime!(2022-02-18 15:30:45.123_456_789 +01).truncate_to_microsecond(),
1459 /// datetime!(2022-02-18 15:30:45.123_456 +01)
1460 /// );
1461 /// ```
1462 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1463 #[inline]
1464 pub const fn truncate_to_microsecond(mut self) -> Self {
1465 self.local_date_time = self.local_date_time.truncate_to_microsecond();
1466 self
1467 }
1468
1469 /// Replace the nanoseconds within the second.
1470 ///
1471 /// ```rust
1472 /// # use time_macros::datetime;
1473 /// assert_eq!(
1474 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_nanosecond(7_008_009),
1475 /// Ok(datetime!(2022-02-18 01:02:03.007_008_009 +01))
1476 /// );
1477 /// 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
1478 /// ```
1479 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1480 #[inline]
1481 pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1482 Ok(
1483 const_try!(self.date_time().replace_nanosecond(nanosecond))
1484 .assume_offset(self.offset()),
1485 )
1486 }
1487}
1488
1489#[cfg(feature = "formatting")]
1490impl OffsetDateTime {
1491 /// Format the `OffsetDateTime` using the provided [format
1492 /// description](crate::format_description).
1493 #[inline]
1494 pub fn format_into(
1495 self,
1496 output: &mut (impl io::Write + ?Sized),
1497 format: &(impl Formattable + ?Sized),
1498 ) -> Result<usize, error::Format> {
1499 format.format_into(output, &self, &mut Default::default(), PrivateMethod)
1500 }
1501
1502 /// Format the `OffsetDateTime` using the provided [format
1503 /// description](crate::format_description).
1504 ///
1505 /// ```rust
1506 /// # use time::format_description;
1507 /// # use time_macros::datetime;
1508 /// let format = format_description::parse_borrowed::<3>(
1509 /// "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
1510 /// sign:mandatory]:[offset_minute]:[offset_second]",
1511 /// )?;
1512 /// assert_eq!(
1513 /// datetime!(2020-01-02 03:04:05 +06:07:08).format(&format)?,
1514 /// "2020-01-02 03:04:05 +06:07:08"
1515 /// );
1516 /// # Ok::<_, time::Error>(())
1517 /// ```
1518 #[inline]
1519 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1520 format.format(&self, &mut Default::default(), PrivateMethod)
1521 }
1522}
1523
1524#[cfg(feature = "parsing")]
1525impl OffsetDateTime {
1526 /// Parse an `OffsetDateTime` from the input using the provided [format
1527 /// description](crate::format_description).
1528 ///
1529 /// ```rust
1530 /// # use time::OffsetDateTime;
1531 /// # use time_macros::{datetime, format_description};
1532 /// let format = format_description!(
1533 /// "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
1534 /// sign:mandatory]:[offset_minute]:[offset_second]"
1535 /// );
1536 /// assert_eq!(
1537 /// OffsetDateTime::parse("2020-01-02 03:04:05 +06:07:08", &format)?,
1538 /// datetime!(2020-01-02 03:04:05 +06:07:08)
1539 /// );
1540 /// # Ok::<_, time::Error>(())
1541 /// ```
1542 #[inline]
1543 pub fn parse(
1544 input: &str,
1545 description: &(impl Parsable + ?Sized),
1546 ) -> Result<Self, error::Parse> {
1547 description.parse_offset_date_time(input.as_bytes(), None, PrivateMethod)
1548 }
1549
1550 /// Parse an `OffsetDateTime` from the input using the provided [format
1551 /// description](crate::format_description) and default values.
1552 ///
1553 /// ```rust
1554 /// # use time::OffsetDateTime;
1555 /// # use time::parsing::Parsed;
1556 /// # use time_macros::{datetime, format_description};
1557 /// let format = format_description!("[year]-[month]-[day] [hour]:[minute]");
1558 /// let defaults = Parsed::new()
1559 /// .with_offset_hour(0).expect("0 is a valid offset hour")
1560 /// .with_offset_minute_signed(0).expect("0 is a valid offset minute");
1561 /// assert_eq!(
1562 /// OffsetDateTime::parse_with_defaults(b"2020-01-02 03:04", &format, defaults)?,
1563 /// datetime!(2020-01-02 03:04 +0:00)
1564 /// );
1565 /// # Ok::<_, time::Error>(())
1566 /// ```
1567 #[inline]
1568 pub fn parse_with_defaults(
1569 input: &[u8],
1570 description: &(impl Parsable + ?Sized),
1571 defaults: Parsed,
1572 ) -> Result<Self, error::Parse> {
1573 description.parse_offset_date_time(input, Some(defaults), PrivateMethod)
1574 }
1575
1576 /// A helper method to check if the `OffsetDateTime` is a valid representation of a leap second.
1577 /// Leap seconds, when parsed, are represented as the preceding nanosecond. However, leap
1578 /// seconds can only occur as the last second of a month UTC.
1579 #[cfg(feature = "parsing")]
1580 #[inline]
1581 pub(crate) const fn is_valid_leap_second_stand_in(self) -> bool {
1582 // This comparison doesn't need to be adjusted for the stored offset, so check it first for
1583 // speed.
1584 if self.nanosecond() != 999_999_999 {
1585 return false;
1586 }
1587
1588 let (year, ordinal, time) = self.to_utc_raw();
1589 let Ok(date) = Date::from_ordinal_date(year, ordinal) else {
1590 return false;
1591 };
1592
1593 time.hour() == 23
1594 && time.minute() == 59
1595 && time.second() == 59
1596 && date.day() == date.month().length(year)
1597 }
1598}
1599
1600// This no longer needs special handling, as the format is fixed and doesn't require anything
1601// advanced. Trait impls can't be deprecated and the info is still useful for other types
1602// implementing `SmartDisplay`, so leave it as-is for now.
1603impl SmartDisplay for OffsetDateTime {
1604 type Metadata = ();
1605
1606 #[inline]
1607 fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> {
1608 let width = self.date_time().metadata(f).unpadded_width()
1609 + self.offset().metadata(f).unpadded_width()
1610 + 1;
1611 Metadata::new(width, self, ())
1612 }
1613
1614 #[inline]
1615 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1616 fmt::Display::fmt(self, f)
1617 }
1618}
1619
1620impl OffsetDateTime {
1621 /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used
1622 /// for the `Display` implementation.
1623 pub(crate) const DISPLAY_BUFFER_SIZE: usize =
1624 PrimitiveDateTime::DISPLAY_BUFFER_SIZE + UtcOffset::DISPLAY_BUFFER_SIZE + 1;
1625
1626 /// Format the `PrimitiveDateTime` into the provided buffer, returning the number of bytes
1627 /// written.
1628 #[inline]
1629 pub(crate) fn fmt_into_buffer(
1630 self,
1631 buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
1632 ) -> usize {
1633 // Safety: The buffer is large enough that the first chunk is in bounds.
1634 let date_time_len = self
1635 .date_time()
1636 .fmt_into_buffer(unsafe { buf.first_chunk_mut().unwrap_unchecked() });
1637 buf[date_time_len].write(b' ');
1638 // Safety: The buffer is large enough that the first chunk is in bounds.
1639 let offset_len = self.offset().fmt_into_buffer(unsafe {
1640 buf[date_time_len + 1..]
1641 .first_chunk_mut()
1642 .unwrap_unchecked()
1643 });
1644 date_time_len + offset_len + 1
1645 }
1646}
1647
1648impl fmt::Display for OffsetDateTime {
1649 #[inline]
1650 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1651 let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1652 let len = self.fmt_into_buffer(&mut buf);
1653 // Safety: All bytes up to `len` have been initialized with ASCII characters.
1654 let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1655 f.pad(s)
1656 }
1657}
1658
1659impl fmt::Debug for OffsetDateTime {
1660 #[inline]
1661 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1662 fmt::Display::fmt(self, f)
1663 }
1664}
1665
1666impl Add<Duration> for OffsetDateTime {
1667 type Output = Self;
1668
1669 /// # Panics
1670 ///
1671 /// This may panic if an overflow occurs.
1672 #[inline]
1673 #[track_caller]
1674 fn add(self, duration: Duration) -> Self::Output {
1675 self.checked_add(duration)
1676 .expect("resulting value is out of range")
1677 }
1678}
1679
1680impl Add<StdDuration> for OffsetDateTime {
1681 type Output = Self;
1682
1683 /// # Panics
1684 ///
1685 /// This may panic if an overflow occurs.
1686 #[inline]
1687 #[track_caller]
1688 fn add(self, duration: StdDuration) -> Self::Output {
1689 let (is_next_day, time) = self.time().adjusting_add_std(duration);
1690
1691 Self::new_in_offset(
1692 if is_next_day {
1693 (self.date() + duration)
1694 .next_day()
1695 .expect("resulting value is out of range")
1696 } else {
1697 self.date() + duration
1698 },
1699 time,
1700 self.offset,
1701 )
1702 }
1703}
1704
1705impl AddAssign<Duration> for OffsetDateTime {
1706 /// # Panics
1707 ///
1708 /// This may panic if an overflow occurs.
1709 #[inline]
1710 #[track_caller]
1711 fn add_assign(&mut self, rhs: Duration) {
1712 *self = *self + rhs;
1713 }
1714}
1715
1716impl AddAssign<StdDuration> for OffsetDateTime {
1717 /// # Panics
1718 ///
1719 /// This may panic if an overflow occurs.
1720 #[inline]
1721 #[track_caller]
1722 fn add_assign(&mut self, rhs: StdDuration) {
1723 *self = *self + rhs;
1724 }
1725}
1726
1727impl Sub<Duration> for OffsetDateTime {
1728 type Output = Self;
1729
1730 /// # Panics
1731 ///
1732 /// This may panic if an overflow occurs.
1733 #[inline]
1734 #[track_caller]
1735 fn sub(self, rhs: Duration) -> Self::Output {
1736 self.checked_sub(rhs)
1737 .expect("resulting value is out of range")
1738 }
1739}
1740
1741impl Sub<StdDuration> for OffsetDateTime {
1742 type Output = Self;
1743
1744 /// # Panics
1745 ///
1746 /// This may panic if an overflow occurs.
1747 #[inline]
1748 #[track_caller]
1749 fn sub(self, duration: StdDuration) -> Self::Output {
1750 let (is_previous_day, time) = self.time().adjusting_sub_std(duration);
1751
1752 Self::new_in_offset(
1753 if is_previous_day {
1754 (self.date() - duration)
1755 .previous_day()
1756 .expect("resulting value is out of range")
1757 } else {
1758 self.date() - duration
1759 },
1760 time,
1761 self.offset,
1762 )
1763 }
1764}
1765
1766impl SubAssign<Duration> for OffsetDateTime {
1767 /// # Panics
1768 ///
1769 /// This may panic if an overflow occurs.
1770 #[inline]
1771 #[track_caller]
1772 fn sub_assign(&mut self, rhs: Duration) {
1773 *self = *self - rhs;
1774 }
1775}
1776
1777impl SubAssign<StdDuration> for OffsetDateTime {
1778 /// # Panics
1779 ///
1780 /// This may panic if an overflow occurs.
1781 #[inline]
1782 #[track_caller]
1783 fn sub_assign(&mut self, rhs: StdDuration) {
1784 *self = *self - rhs;
1785 }
1786}
1787
1788impl Sub for OffsetDateTime {
1789 type Output = Duration;
1790
1791 #[inline]
1792 fn sub(self, rhs: Self) -> Self::Output {
1793 let base = self.date_time() - rhs.date_time();
1794 let adjustment = Duration::seconds(
1795 (self.offset.whole_seconds() - rhs.offset.whole_seconds()).widen::<i64>(),
1796 );
1797 base - adjustment
1798 }
1799}