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