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_t(Minute) => minute);
311 cascade!(second in 0..Second::per_t(Minute) => minute);
312 cascade!(minute in 0..Minute::per_t(Hour) => hour);
313 cascade!(minute in 0..Minute::per_t(Hour) => hour);
314 cascade!(hour in 0..Hour::per_t(Day) => ordinal);
315 cascade!(hour in 0..Hour::per_t(Day) => 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_t::<i64>(Day)) as i32,
381 )
382 };
383
384 let seconds_within_day = timestamp.rem_euclid(Second::per_t(Day));
385 // Safety: All values are in range.
386 let time = unsafe {
387 Time::__from_hms_nanos_unchecked(
388 (seconds_within_day / Second::per_t::<i64>(Hour)) as u8,
389 ((seconds_within_day % Second::per_t::<i64>(Hour)) / Minute::per_t::<i64>(Hour))
390 as u8,
391 (seconds_within_day % Second::per_t::<i64>(Minute)) as u8,
392 0,
393 )
394 };
395
396 Ok(Self::new_in_offset(date, time, UtcOffset::UTC))
397 }
398
399 /// Construct an `OffsetDateTime` from the provided Unix timestamp (in nanoseconds). Calling
400 /// `.offset()` on the resulting value is guaranteed to return UTC.
401 ///
402 /// ```rust
403 /// # use time::OffsetDateTime;
404 /// # use time_macros::datetime;
405 /// assert_eq!(
406 /// OffsetDateTime::from_unix_timestamp_nanos(0),
407 /// Ok(OffsetDateTime::UNIX_EPOCH),
408 /// );
409 /// assert_eq!(
410 /// OffsetDateTime::from_unix_timestamp_nanos(1_546_300_800_000_000_000),
411 /// Ok(datetime!(2019-01-01 0:00 UTC)),
412 /// );
413 /// ```
414 pub const fn from_unix_timestamp_nanos(timestamp: i128) -> Result<Self, error::ComponentRange> {
415 let datetime = const_try!(Self::from_unix_timestamp(div_floor!(
416 timestamp,
417 Nanosecond::per_t::<i128>(Second)
418 ) as i64));
419
420 Ok(Self::new_in_offset(
421 datetime.date(),
422 // Safety: `nanosecond` is in range due to `rem_euclid`.
423 unsafe {
424 Time::__from_hms_nanos_unchecked(
425 datetime.hour(),
426 datetime.minute(),
427 datetime.second(),
428 timestamp.rem_euclid(Nanosecond::per_t(Second)) as u32,
429 )
430 },
431 UtcOffset::UTC,
432 ))
433 }
434
435 /// Get the [`UtcOffset`].
436 ///
437 /// ```rust
438 /// # use time_macros::{datetime, offset};
439 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).offset(), offset!(UTC));
440 /// assert_eq!(datetime!(2019-01-01 0:00 +1).offset(), offset!(+1));
441 /// ```
442 pub const fn offset(self) -> UtcOffset {
443 self.offset
444 }
445
446 /// Get the [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
447 ///
448 /// ```rust
449 /// # use time_macros::datetime;
450 /// assert_eq!(datetime!(1970-01-01 0:00 UTC).unix_timestamp(), 0);
451 /// assert_eq!(datetime!(1970-01-01 0:00 -1).unix_timestamp(), 3_600);
452 /// ```
453 pub const fn unix_timestamp(self) -> i64 {
454 let days = (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64)
455 * Second::per_t::<i64>(Day);
456 let hours = self.hour() as i64 * Second::per_t::<i64>(Hour);
457 let minutes = self.minute() as i64 * Second::per_t::<i64>(Minute);
458 let seconds = self.second() as i64;
459 let offset_seconds = self.offset.whole_seconds() as i64;
460 days + hours + minutes + seconds - offset_seconds
461 }
462
463 /// Get the Unix timestamp in nanoseconds.
464 ///
465 /// ```rust
466 /// use time_macros::datetime;
467 /// assert_eq!(datetime!(1970-01-01 0:00 UTC).unix_timestamp_nanos(), 0);
468 /// assert_eq!(
469 /// datetime!(1970-01-01 0:00 -1).unix_timestamp_nanos(),
470 /// 3_600_000_000_000,
471 /// );
472 /// ```
473 pub const fn unix_timestamp_nanos(self) -> i128 {
474 self.unix_timestamp() as i128 * Nanosecond::per_t::<i128>(Second)
475 + self.nanosecond() as i128
476 }
477
478 /// Get the [`PrimitiveDateTime`] in the stored offset.
479 pub(crate) const fn date_time(self) -> PrimitiveDateTime {
480 self.local_date_time
481 }
482
483 /// Get the [`Date`] in the stored offset.
484 ///
485 /// ```rust
486 /// # use time_macros::{date, datetime, offset};
487 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).date(), date!(2019-01-01));
488 /// assert_eq!(
489 /// datetime!(2019-01-01 0:00 UTC)
490 /// .to_offset(offset!(-1))
491 /// .date(),
492 /// date!(2018-12-31),
493 /// );
494 /// ```
495 pub const fn date(self) -> Date {
496 self.date_time().date()
497 }
498
499 /// Get the [`Time`] in the stored offset.
500 ///
501 /// ```rust
502 /// # use time_macros::{datetime, offset, time};
503 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).time(), time!(0:00));
504 /// assert_eq!(
505 /// datetime!(2019-01-01 0:00 UTC)
506 /// .to_offset(offset!(-1))
507 /// .time(),
508 /// time!(23:00)
509 /// );
510 /// ```
511 pub const fn time(self) -> Time {
512 self.date_time().time()
513 }
514
515 /// Get the year of the date in the stored offset.
516 ///
517 /// ```rust
518 /// # use time_macros::{datetime, offset};
519 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).year(), 2019);
520 /// assert_eq!(
521 /// datetime!(2019-12-31 23:00 UTC)
522 /// .to_offset(offset!(+1))
523 /// .year(),
524 /// 2020,
525 /// );
526 /// assert_eq!(datetime!(2020-01-01 0:00 UTC).year(), 2020);
527 /// ```
528 pub const fn year(self) -> i32 {
529 self.date().year()
530 }
531
532 /// Get the month of the date in the stored offset.
533 ///
534 /// ```rust
535 /// # use time::Month;
536 /// # use time_macros::{datetime, offset};
537 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).month(), Month::January);
538 /// assert_eq!(
539 /// datetime!(2019-12-31 23:00 UTC)
540 /// .to_offset(offset!(+1))
541 /// .month(),
542 /// Month::January,
543 /// );
544 /// ```
545 pub const fn month(self) -> Month {
546 self.date().month()
547 }
548
549 /// Get the day of the date in the stored offset.
550 ///
551 /// The returned value will always be in the range `1..=31`.
552 ///
553 /// ```rust
554 /// # use time_macros::{datetime, offset};
555 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).day(), 1);
556 /// assert_eq!(
557 /// datetime!(2019-12-31 23:00 UTC)
558 /// .to_offset(offset!(+1))
559 /// .day(),
560 /// 1,
561 /// );
562 /// ```
563 pub const fn day(self) -> u8 {
564 self.date().day()
565 }
566
567 /// Get the day of the year of the date in the stored offset.
568 ///
569 /// The returned value will always be in the range `1..=366`.
570 ///
571 /// ```rust
572 /// # use time_macros::{datetime, offset};
573 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).ordinal(), 1);
574 /// assert_eq!(
575 /// datetime!(2019-12-31 23:00 UTC)
576 /// .to_offset(offset!(+1))
577 /// .ordinal(),
578 /// 1,
579 /// );
580 /// ```
581 pub const fn ordinal(self) -> u16 {
582 self.date().ordinal()
583 }
584
585 /// Get the ISO week number of the date in the stored offset.
586 ///
587 /// The returned value will always be in the range `1..=53`.
588 ///
589 /// ```rust
590 /// # use time_macros::datetime;
591 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).iso_week(), 1);
592 /// assert_eq!(datetime!(2020-01-01 0:00 UTC).iso_week(), 1);
593 /// assert_eq!(datetime!(2020-12-31 0:00 UTC).iso_week(), 53);
594 /// assert_eq!(datetime!(2021-01-01 0:00 UTC).iso_week(), 53);
595 /// ```
596 pub const fn iso_week(self) -> u8 {
597 self.date().iso_week()
598 }
599
600 /// Get the week number where week 1 begins on the first Sunday.
601 ///
602 /// The returned value will always be in the range `0..=53`.
603 ///
604 /// ```rust
605 /// # use time_macros::datetime;
606 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).sunday_based_week(), 0);
607 /// assert_eq!(datetime!(2020-01-01 0:00 UTC).sunday_based_week(), 0);
608 /// assert_eq!(datetime!(2020-12-31 0:00 UTC).sunday_based_week(), 52);
609 /// assert_eq!(datetime!(2021-01-01 0:00 UTC).sunday_based_week(), 0);
610 /// ```
611 pub const fn sunday_based_week(self) -> u8 {
612 self.date().sunday_based_week()
613 }
614
615 /// Get the week number where week 1 begins on the first Monday.
616 ///
617 /// The returned value will always be in the range `0..=53`.
618 ///
619 /// ```rust
620 /// # use time_macros::datetime;
621 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).monday_based_week(), 0);
622 /// assert_eq!(datetime!(2020-01-01 0:00 UTC).monday_based_week(), 0);
623 /// assert_eq!(datetime!(2020-12-31 0:00 UTC).monday_based_week(), 52);
624 /// assert_eq!(datetime!(2021-01-01 0:00 UTC).monday_based_week(), 0);
625 /// ```
626 pub const fn monday_based_week(self) -> u8 {
627 self.date().monday_based_week()
628 }
629
630 /// Get the year, month, and day.
631 ///
632 /// ```rust
633 /// # use time::Month;
634 /// # use time_macros::datetime;
635 /// assert_eq!(
636 /// datetime!(2019-01-01 0:00 UTC).to_calendar_date(),
637 /// (2019, Month::January, 1)
638 /// );
639 /// ```
640 pub const fn to_calendar_date(self) -> (i32, Month, u8) {
641 self.date().to_calendar_date()
642 }
643
644 /// Get the year and ordinal day number.
645 ///
646 /// ```rust
647 /// # use time_macros::datetime;
648 /// assert_eq!(
649 /// datetime!(2019-01-01 0:00 UTC).to_ordinal_date(),
650 /// (2019, 1)
651 /// );
652 /// ```
653 pub const fn to_ordinal_date(self) -> (i32, u16) {
654 self.date().to_ordinal_date()
655 }
656
657 /// Get the ISO 8601 year, week number, and weekday.
658 ///
659 /// ```rust
660 /// # use time::Weekday::*;
661 /// # use time_macros::datetime;
662 /// assert_eq!(
663 /// datetime!(2019-01-01 0:00 UTC).to_iso_week_date(),
664 /// (2019, 1, Tuesday)
665 /// );
666 /// assert_eq!(
667 /// datetime!(2019-10-04 0:00 UTC).to_iso_week_date(),
668 /// (2019, 40, Friday)
669 /// );
670 /// assert_eq!(
671 /// datetime!(2020-01-01 0:00 UTC).to_iso_week_date(),
672 /// (2020, 1, Wednesday)
673 /// );
674 /// assert_eq!(
675 /// datetime!(2020-12-31 0:00 UTC).to_iso_week_date(),
676 /// (2020, 53, Thursday)
677 /// );
678 /// assert_eq!(
679 /// datetime!(2021-01-01 0:00 UTC).to_iso_week_date(),
680 /// (2020, 53, Friday)
681 /// );
682 /// ```
683 pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
684 self.date().to_iso_week_date()
685 }
686
687 /// Get the weekday of the date in the stored offset.
688 ///
689 /// ```rust
690 /// # use time::Weekday::*;
691 /// # use time_macros::datetime;
692 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).weekday(), Tuesday);
693 /// assert_eq!(datetime!(2019-02-01 0:00 UTC).weekday(), Friday);
694 /// assert_eq!(datetime!(2019-03-01 0:00 UTC).weekday(), Friday);
695 /// ```
696 pub const fn weekday(self) -> Weekday {
697 self.date().weekday()
698 }
699
700 /// Get the Julian day for the date. The time is not taken into account for this calculation.
701 ///
702 /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
703 /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
704 ///
705 /// ```rust
706 /// # use time_macros::datetime;
707 /// assert_eq!(datetime!(-4713-11-24 0:00 UTC).to_julian_day(), 0);
708 /// assert_eq!(datetime!(2000-01-01 0:00 UTC).to_julian_day(), 2_451_545);
709 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).to_julian_day(), 2_458_485);
710 /// assert_eq!(datetime!(2019-12-31 0:00 UTC).to_julian_day(), 2_458_849);
711 /// ```
712 pub const fn to_julian_day(self) -> i32 {
713 self.date().to_julian_day()
714 }
715
716 /// Get the clock hour, minute, and second.
717 ///
718 /// ```rust
719 /// # use time_macros::datetime;
720 /// assert_eq!(datetime!(2020-01-01 0:00:00 UTC).to_hms(), (0, 0, 0));
721 /// assert_eq!(datetime!(2020-01-01 23:59:59 UTC).to_hms(), (23, 59, 59));
722 /// ```
723 pub const fn to_hms(self) -> (u8, u8, u8) {
724 self.time().as_hms()
725 }
726
727 /// Get the clock hour, minute, second, and millisecond.
728 ///
729 /// ```rust
730 /// # use time_macros::datetime;
731 /// assert_eq!(
732 /// datetime!(2020-01-01 0:00:00 UTC).to_hms_milli(),
733 /// (0, 0, 0, 0)
734 /// );
735 /// assert_eq!(
736 /// datetime!(2020-01-01 23:59:59.999 UTC).to_hms_milli(),
737 /// (23, 59, 59, 999)
738 /// );
739 /// ```
740 pub const fn to_hms_milli(self) -> (u8, u8, u8, u16) {
741 self.time().as_hms_milli()
742 }
743
744 /// Get the clock hour, minute, second, and microsecond.
745 ///
746 /// ```rust
747 /// # use time_macros::datetime;
748 /// assert_eq!(
749 /// datetime!(2020-01-01 0:00:00 UTC).to_hms_micro(),
750 /// (0, 0, 0, 0)
751 /// );
752 /// assert_eq!(
753 /// datetime!(2020-01-01 23:59:59.999_999 UTC).to_hms_micro(),
754 /// (23, 59, 59, 999_999)
755 /// );
756 /// ```
757 pub const fn to_hms_micro(self) -> (u8, u8, u8, u32) {
758 self.time().as_hms_micro()
759 }
760
761 /// Get the clock hour, minute, second, and nanosecond.
762 ///
763 /// ```rust
764 /// # use time_macros::datetime;
765 /// assert_eq!(
766 /// datetime!(2020-01-01 0:00:00 UTC).to_hms_nano(),
767 /// (0, 0, 0, 0)
768 /// );
769 /// assert_eq!(
770 /// datetime!(2020-01-01 23:59:59.999_999_999 UTC).to_hms_nano(),
771 /// (23, 59, 59, 999_999_999)
772 /// );
773 /// ```
774 pub const fn to_hms_nano(self) -> (u8, u8, u8, u32) {
775 self.time().as_hms_nano()
776 }
777
778 /// Get the clock hour in the stored offset.
779 ///
780 /// The returned value will always be in the range `0..24`.
781 ///
782 /// ```rust
783 /// # use time_macros::{datetime, offset};
784 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).hour(), 0);
785 /// assert_eq!(
786 /// datetime!(2019-01-01 23:59:59 UTC)
787 /// .to_offset(offset!(-2))
788 /// .hour(),
789 /// 21,
790 /// );
791 /// ```
792 pub const fn hour(self) -> u8 {
793 self.time().hour()
794 }
795
796 /// Get the minute within the hour in the stored offset.
797 ///
798 /// The returned value will always be in the range `0..60`.
799 ///
800 /// ```rust
801 /// # use time_macros::{datetime, offset};
802 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).minute(), 0);
803 /// assert_eq!(
804 /// datetime!(2019-01-01 23:59:59 UTC)
805 /// .to_offset(offset!(+0:30))
806 /// .minute(),
807 /// 29,
808 /// );
809 /// ```
810 pub const fn minute(self) -> u8 {
811 self.time().minute()
812 }
813
814 /// Get the second within the minute in the stored offset.
815 ///
816 /// The returned value will always be in the range `0..60`.
817 ///
818 /// ```rust
819 /// # use time_macros::{datetime, offset};
820 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).second(), 0);
821 /// assert_eq!(
822 /// datetime!(2019-01-01 23:59:59 UTC)
823 /// .to_offset(offset!(+0:00:30))
824 /// .second(),
825 /// 29,
826 /// );
827 /// ```
828 pub const fn second(self) -> u8 {
829 self.time().second()
830 }
831
832 // Because a `UtcOffset` is limited in resolution to one second, any subsecond value will not
833 // change when adjusting for the offset.
834
835 /// Get the milliseconds within the second in the stored offset.
836 ///
837 /// The returned value will always be in the range `0..1_000`.
838 ///
839 /// ```rust
840 /// # use time_macros::datetime;
841 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).millisecond(), 0);
842 /// assert_eq!(datetime!(2019-01-01 23:59:59.999 UTC).millisecond(), 999);
843 /// ```
844 pub const fn millisecond(self) -> u16 {
845 self.time().millisecond()
846 }
847
848 /// Get the microseconds within the second in the stored offset.
849 ///
850 /// The returned value will always be in the range `0..1_000_000`.
851 ///
852 /// ```rust
853 /// # use time_macros::datetime;
854 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).microsecond(), 0);
855 /// assert_eq!(
856 /// datetime!(2019-01-01 23:59:59.999_999 UTC).microsecond(),
857 /// 999_999,
858 /// );
859 /// ```
860 pub const fn microsecond(self) -> u32 {
861 self.time().microsecond()
862 }
863
864 /// Get the nanoseconds within the second in the stored offset.
865 ///
866 /// The returned value will always be in the range `0..1_000_000_000`.
867 ///
868 /// ```rust
869 /// # use time_macros::datetime;
870 /// assert_eq!(datetime!(2019-01-01 0:00 UTC).nanosecond(), 0);
871 /// assert_eq!(
872 /// datetime!(2019-01-01 23:59:59.999_999_999 UTC).nanosecond(),
873 /// 999_999_999,
874 /// );
875 /// ```
876 pub const fn nanosecond(self) -> u32 {
877 self.time().nanosecond()
878 }
879
880 /// Computes `self + duration`, returning `None` if an overflow occurred.
881 ///
882 /// ```
883 /// # use time::{Date, ext::NumericalDuration};
884 /// # use time_macros::{datetime, offset};
885 /// let datetime = Date::MIN.midnight().assume_offset(offset!(+10));
886 /// assert_eq!(datetime.checked_add((-2).days()), None);
887 ///
888 /// let datetime = Date::MAX.midnight().assume_offset(offset!(+10));
889 /// assert_eq!(datetime.checked_add(2.days()), None);
890 ///
891 /// assert_eq!(
892 /// datetime!(2019-11-25 15:30 +10).checked_add(27.hours()),
893 /// Some(datetime!(2019-11-26 18:30 +10))
894 /// );
895 /// ```
896 pub const fn checked_add(self, duration: Duration) -> Option<Self> {
897 Some(const_try_opt!(self.date_time().checked_add(duration)).assume_offset(self.offset()))
898 }
899
900 /// Computes `self - duration`, returning `None` if an overflow occurred.
901 ///
902 /// ```
903 /// # use time::{Date, ext::NumericalDuration};
904 /// # use time_macros::{datetime, offset};
905 /// let datetime = Date::MIN.midnight().assume_offset(offset!(+10));
906 /// assert_eq!(datetime.checked_sub(2.days()), None);
907 ///
908 /// let datetime = Date::MAX.midnight().assume_offset(offset!(+10));
909 /// assert_eq!(datetime.checked_sub((-2).days()), None);
910 ///
911 /// assert_eq!(
912 /// datetime!(2019-11-25 15:30 +10).checked_sub(27.hours()),
913 /// Some(datetime!(2019-11-24 12:30 +10))
914 /// );
915 /// ```
916 pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
917 Some(const_try_opt!(self.date_time().checked_sub(duration)).assume_offset(self.offset()))
918 }
919
920 /// Computes `self + duration`, saturating value on overflow.
921 ///
922 /// ```
923 /// # use time::ext::NumericalDuration;
924 /// # use time_macros::datetime;
925 /// assert_eq!(
926 #[cfg_attr(
927 feature = "large-dates",
928 doc = " datetime!(-999999-01-01 0:00 +10).saturating_add((-2).days()),"
929 )]
930 #[cfg_attr(feature = "large-dates", doc = " datetime!(-999999-01-01 0:00 +10)")]
931 #[cfg_attr(
932 not(feature = "large-dates"),
933 doc = " datetime!(-9999-01-01 0:00 +10).saturating_add((-2).days()),"
934 )]
935 #[cfg_attr(
936 not(feature = "large-dates"),
937 doc = " datetime!(-9999-01-01 0:00 +10)"
938 )]
939 /// );
940 ///
941 /// assert_eq!(
942 #[cfg_attr(
943 feature = "large-dates",
944 doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10).saturating_add(2.days()),"
945 )]
946 #[cfg_attr(
947 feature = "large-dates",
948 doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10)"
949 )]
950 #[cfg_attr(
951 not(feature = "large-dates"),
952 doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10).saturating_add(2.days()),"
953 )]
954 #[cfg_attr(
955 not(feature = "large-dates"),
956 doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10)"
957 )]
958 /// );
959 ///
960 /// assert_eq!(
961 /// datetime!(2019-11-25 15:30 +10).saturating_add(27.hours()),
962 /// datetime!(2019-11-26 18:30 +10)
963 /// );
964 /// ```
965 pub const fn saturating_add(self, duration: Duration) -> Self {
966 if let Some(datetime) = self.checked_add(duration) {
967 datetime
968 } else if duration.is_negative() {
969 PrimitiveDateTime::MIN.assume_offset(self.offset())
970 } else {
971 PrimitiveDateTime::MAX.assume_offset(self.offset())
972 }
973 }
974
975 /// Computes `self - duration`, saturating value on overflow.
976 ///
977 /// ```
978 /// # use time::ext::NumericalDuration;
979 /// # use time_macros::datetime;
980 /// assert_eq!(
981 #[cfg_attr(
982 feature = "large-dates",
983 doc = " datetime!(-999999-01-01 0:00 +10).saturating_sub(2.days()),"
984 )]
985 #[cfg_attr(feature = "large-dates", doc = " datetime!(-999999-01-01 0:00 +10)")]
986 #[cfg_attr(
987 not(feature = "large-dates"),
988 doc = " datetime!(-9999-01-01 0:00 +10).saturating_sub(2.days()),"
989 )]
990 #[cfg_attr(
991 not(feature = "large-dates"),
992 doc = " datetime!(-9999-01-01 0:00 +10)"
993 )]
994 /// );
995 ///
996 /// assert_eq!(
997 #[cfg_attr(
998 feature = "large-dates",
999 doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10).saturating_sub((-2).days()),"
1000 )]
1001 #[cfg_attr(
1002 feature = "large-dates",
1003 doc = " datetime!(+999999-12-31 23:59:59.999_999_999 +10)"
1004 )]
1005 #[cfg_attr(
1006 not(feature = "large-dates"),
1007 doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10).saturating_sub((-2).days()),"
1008 )]
1009 #[cfg_attr(
1010 not(feature = "large-dates"),
1011 doc = " datetime!(+9999-12-31 23:59:59.999_999_999 +10)"
1012 )]
1013 /// );
1014 ///
1015 /// assert_eq!(
1016 /// datetime!(2019-11-25 15:30 +10).saturating_sub(27.hours()),
1017 /// datetime!(2019-11-24 12:30 +10)
1018 /// );
1019 /// ```
1020 pub const fn saturating_sub(self, duration: Duration) -> Self {
1021 if let Some(datetime) = self.checked_sub(duration) {
1022 datetime
1023 } else if duration.is_negative() {
1024 PrimitiveDateTime::MAX.assume_offset(self.offset())
1025 } else {
1026 PrimitiveDateTime::MIN.assume_offset(self.offset())
1027 }
1028 }
1029}
1030
1031/// Methods that replace part of the `OffsetDateTime`.
1032impl OffsetDateTime {
1033 /// Replace the time, which is assumed to be in the stored offset. The date and offset
1034 /// components are unchanged.
1035 ///
1036 /// ```rust
1037 /// # use time_macros::{datetime, time};
1038 /// assert_eq!(
1039 /// datetime!(2020-01-01 5:00 UTC).replace_time(time!(12:00)),
1040 /// datetime!(2020-01-01 12:00 UTC)
1041 /// );
1042 /// assert_eq!(
1043 /// datetime!(2020-01-01 12:00 -5).replace_time(time!(7:00)),
1044 /// datetime!(2020-01-01 7:00 -5)
1045 /// );
1046 /// assert_eq!(
1047 /// datetime!(2020-01-01 0:00 +1).replace_time(time!(12:00)),
1048 /// datetime!(2020-01-01 12:00 +1)
1049 /// );
1050 /// ```
1051 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1052 pub const fn replace_time(self, time: Time) -> Self {
1053 Self::new_in_offset(self.date(), time, self.offset())
1054 }
1055
1056 /// Replace the date, which is assumed to be in the stored offset. The time and offset
1057 /// components are unchanged.
1058 ///
1059 /// ```rust
1060 /// # use time_macros::{datetime, date};
1061 /// assert_eq!(
1062 /// datetime!(2020-01-01 12:00 UTC).replace_date(date!(2020-01-30)),
1063 /// datetime!(2020-01-30 12:00 UTC)
1064 /// );
1065 /// assert_eq!(
1066 /// datetime!(2020-01-01 0:00 +1).replace_date(date!(2020-01-30)),
1067 /// datetime!(2020-01-30 0:00 +1)
1068 /// );
1069 /// ```
1070 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1071 pub const fn replace_date(self, date: Date) -> Self {
1072 Self::new_in_offset(date, self.time(), self.offset())
1073 }
1074
1075 /// Replace the date and time, which are assumed to be in the stored offset. The offset
1076 /// component remains unchanged.
1077 ///
1078 /// ```rust
1079 /// # use time_macros::datetime;
1080 /// assert_eq!(
1081 /// datetime!(2020-01-01 12:00 UTC).replace_date_time(datetime!(2020-01-30 16:00)),
1082 /// datetime!(2020-01-30 16:00 UTC)
1083 /// );
1084 /// assert_eq!(
1085 /// datetime!(2020-01-01 12:00 +1).replace_date_time(datetime!(2020-01-30 0:00)),
1086 /// datetime!(2020-01-30 0:00 +1)
1087 /// );
1088 /// ```
1089 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1090 pub const fn replace_date_time(self, date_time: PrimitiveDateTime) -> Self {
1091 date_time.assume_offset(self.offset())
1092 }
1093
1094 /// Replace the offset. The date and time components remain unchanged.
1095 ///
1096 /// ```rust
1097 /// # use time_macros::{datetime, offset};
1098 /// assert_eq!(
1099 /// datetime!(2020-01-01 0:00 UTC).replace_offset(offset!(-5)),
1100 /// datetime!(2020-01-01 0:00 -5)
1101 /// );
1102 /// ```
1103 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1104 pub const fn replace_offset(self, offset: UtcOffset) -> Self {
1105 self.date_time().assume_offset(offset)
1106 }
1107
1108 /// Replace the year. The month and day will be unchanged.
1109 ///
1110 /// ```rust
1111 /// # use time_macros::datetime;
1112 /// assert_eq!(
1113 /// datetime!(2022-02-18 12:00 +01).replace_year(2019),
1114 /// Ok(datetime!(2019-02-18 12:00 +01))
1115 /// );
1116 /// 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
1117 /// 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
1118 /// ```
1119 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1120 pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
1121 Ok(const_try!(self.date_time().replace_year(year)).assume_offset(self.offset()))
1122 }
1123
1124 /// Replace the month of the year.
1125 ///
1126 /// ```rust
1127 /// # use time_macros::datetime;
1128 /// # use time::Month;
1129 /// assert_eq!(
1130 /// datetime!(2022-02-18 12:00 +01).replace_month(Month::January),
1131 /// Ok(datetime!(2022-01-18 12:00 +01))
1132 /// );
1133 /// assert!(datetime!(2022-01-30 12:00 +01).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
1134 /// ```
1135 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1136 pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
1137 Ok(const_try!(self.date_time().replace_month(month)).assume_offset(self.offset()))
1138 }
1139
1140 /// Replace the day of the month.
1141 ///
1142 /// ```rust
1143 /// # use time_macros::datetime;
1144 /// assert_eq!(
1145 /// datetime!(2022-02-18 12:00 +01).replace_day(1),
1146 /// Ok(datetime!(2022-02-01 12:00 +01))
1147 /// );
1148 /// assert!(datetime!(2022-02-18 12:00 +01).replace_day(0).is_err()); // 00 isn't a valid day
1149 /// assert!(datetime!(2022-02-18 12:00 +01).replace_day(30).is_err()); // 30 isn't a valid day in February
1150 /// ```
1151 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1152 pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
1153 Ok(const_try!(self.date_time().replace_day(day)).assume_offset(self.offset()))
1154 }
1155
1156 /// Replace the day of the year.
1157 ///
1158 /// ```rust
1159 /// # use time_macros::datetime;
1160 /// assert_eq!(datetime!(2022-049 12:00 +01).replace_ordinal(1), Ok(datetime!(2022-001 12:00 +01)));
1161 /// assert!(datetime!(2022-049 12:00 +01).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
1162 /// assert!(datetime!(2022-049 12:00 +01).replace_ordinal(366).is_err()); // 2022 isn't a leap year
1163 /// ```
1164 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1165 pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
1166 Ok(const_try!(self.date_time().replace_ordinal(ordinal)).assume_offset(self.offset()))
1167 }
1168
1169 /// Replace the clock hour.
1170 ///
1171 /// ```rust
1172 /// # use time_macros::datetime;
1173 /// assert_eq!(
1174 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_hour(7),
1175 /// Ok(datetime!(2022-02-18 07:02:03.004_005_006 +01))
1176 /// );
1177 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_hour(24).is_err()); // 24 isn't a valid hour
1178 /// ```
1179 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1180 pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
1181 Ok(const_try!(self.date_time().replace_hour(hour)).assume_offset(self.offset()))
1182 }
1183
1184 /// Replace the minutes within the hour.
1185 ///
1186 /// ```rust
1187 /// # use time_macros::datetime;
1188 /// assert_eq!(
1189 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_minute(7),
1190 /// Ok(datetime!(2022-02-18 01:07:03.004_005_006 +01))
1191 /// );
1192 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_minute(60).is_err()); // 60 isn't a valid minute
1193 /// ```
1194 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1195 pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
1196 Ok(const_try!(self.date_time().replace_minute(minute)).assume_offset(self.offset()))
1197 }
1198
1199 /// Replace the seconds within the minute.
1200 ///
1201 /// ```rust
1202 /// # use time_macros::datetime;
1203 /// assert_eq!(
1204 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_second(7),
1205 /// Ok(datetime!(2022-02-18 01:02:07.004_005_006 +01))
1206 /// );
1207 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_second(60).is_err()); // 60 isn't a valid second
1208 /// ```
1209 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1210 pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
1211 Ok(const_try!(self.date_time().replace_second(second)).assume_offset(self.offset()))
1212 }
1213
1214 /// Replace the milliseconds within the second.
1215 ///
1216 /// ```rust
1217 /// # use time_macros::datetime;
1218 /// assert_eq!(
1219 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_millisecond(7),
1220 /// Ok(datetime!(2022-02-18 01:02:03.007 +01))
1221 /// );
1222 /// 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
1223 /// ```
1224 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1225 pub const fn replace_millisecond(
1226 self,
1227 millisecond: u16,
1228 ) -> Result<Self, error::ComponentRange> {
1229 Ok(
1230 const_try!(self.date_time().replace_millisecond(millisecond))
1231 .assume_offset(self.offset()),
1232 )
1233 }
1234
1235 /// Replace the microseconds within the second.
1236 ///
1237 /// ```rust
1238 /// # use time_macros::datetime;
1239 /// assert_eq!(
1240 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_microsecond(7_008),
1241 /// Ok(datetime!(2022-02-18 01:02:03.007_008 +01))
1242 /// );
1243 /// 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
1244 /// ```
1245 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1246 pub const fn replace_microsecond(
1247 self,
1248 microsecond: u32,
1249 ) -> Result<Self, error::ComponentRange> {
1250 Ok(
1251 const_try!(self.date_time().replace_microsecond(microsecond))
1252 .assume_offset(self.offset()),
1253 )
1254 }
1255
1256 /// Replace the nanoseconds within the second.
1257 ///
1258 /// ```rust
1259 /// # use time_macros::datetime;
1260 /// assert_eq!(
1261 /// datetime!(2022-02-18 01:02:03.004_005_006 +01).replace_nanosecond(7_008_009),
1262 /// Ok(datetime!(2022-02-18 01:02:03.007_008_009 +01))
1263 /// );
1264 /// 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
1265 /// ```
1266 #[must_use = "This method does not mutate the original `OffsetDateTime`."]
1267 pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1268 Ok(
1269 const_try!(self.date_time().replace_nanosecond(nanosecond))
1270 .assume_offset(self.offset()),
1271 )
1272 }
1273}
1274
1275#[cfg(feature = "formatting")]
1276impl OffsetDateTime {
1277 /// Format the `OffsetDateTime` using the provided [format
1278 /// description](crate::format_description).
1279 pub fn format_into(
1280 self,
1281 output: &mut (impl io::Write + ?Sized),
1282 format: &(impl Formattable + ?Sized),
1283 ) -> Result<usize, error::Format> {
1284 format.format_into(
1285 output,
1286 Some(self.date()),
1287 Some(self.time()),
1288 Some(self.offset()),
1289 )
1290 }
1291
1292 /// Format the `OffsetDateTime` using the provided [format
1293 /// description](crate::format_description).
1294 ///
1295 /// ```rust
1296 /// # use time::format_description;
1297 /// # use time_macros::datetime;
1298 /// let format = format_description::parse(
1299 /// "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
1300 /// sign:mandatory]:[offset_minute]:[offset_second]",
1301 /// )?;
1302 /// assert_eq!(
1303 /// datetime!(2020-01-02 03:04:05 +06:07:08).format(&format)?,
1304 /// "2020-01-02 03:04:05 +06:07:08"
1305 /// );
1306 /// # Ok::<_, time::Error>(())
1307 /// ```
1308 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1309 format.format(Some(self.date()), Some(self.time()), Some(self.offset()))
1310 }
1311}
1312
1313#[cfg(feature = "parsing")]
1314impl OffsetDateTime {
1315 /// Parse an `OffsetDateTime` from the input using the provided [format
1316 /// description](crate::format_description).
1317 ///
1318 /// ```rust
1319 /// # use time::OffsetDateTime;
1320 /// # use time_macros::{datetime, format_description};
1321 /// let format = format_description!(
1322 /// "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
1323 /// sign:mandatory]:[offset_minute]:[offset_second]"
1324 /// );
1325 /// assert_eq!(
1326 /// OffsetDateTime::parse("2020-01-02 03:04:05 +06:07:08", &format)?,
1327 /// datetime!(2020-01-02 03:04:05 +06:07:08)
1328 /// );
1329 /// # Ok::<_, time::Error>(())
1330 /// ```
1331 pub fn parse(
1332 input: &str,
1333 description: &(impl Parsable + ?Sized),
1334 ) -> Result<Self, error::Parse> {
1335 description.parse_offset_date_time(input.as_bytes())
1336 }
1337
1338 /// A helper method to check if the `OffsetDateTime` is a valid representation of a leap second.
1339 /// Leap seconds, when parsed, are represented as the preceding nanosecond. However, leap
1340 /// seconds can only occur as the last second of a month UTC.
1341 #[cfg(feature = "parsing")]
1342 pub(crate) const fn is_valid_leap_second_stand_in(self) -> bool {
1343 // This comparison doesn't need to be adjusted for the stored offset, so check it first for
1344 // speed.
1345 if self.nanosecond() != 999_999_999 {
1346 return false;
1347 }
1348
1349 let (year, ordinal, time) = self.to_offset_raw(UtcOffset::UTC);
1350 let Ok(date) = Date::from_ordinal_date(year, ordinal) else {
1351 return false;
1352 };
1353
1354 time.hour() == 23
1355 && time.minute() == 59
1356 && time.second() == 59
1357 && date.day() == date.month().length(year)
1358 }
1359}
1360
1361impl SmartDisplay for OffsetDateTime {
1362 type Metadata = ();
1363
1364 fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
1365 let width =
1366 smart_display::padded_width_of!(self.date(), " ", self.time(), " ", self.offset());
1367 Metadata::new(width, self, ())
1368 }
1369
1370 fn fmt_with_metadata(
1371 &self,
1372 f: &mut fmt::Formatter<'_>,
1373 metadata: Metadata<Self>,
1374 ) -> fmt::Result {
1375 f.pad_with_width(
1376 metadata.unpadded_width(),
1377 format_args!("{} {} {}", self.date(), self.time(), self.offset()),
1378 )
1379 }
1380}
1381
1382impl fmt::Display for OffsetDateTime {
1383 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1384 SmartDisplay::fmt(self, f)
1385 }
1386}
1387
1388impl fmt::Debug for OffsetDateTime {
1389 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1390 fmt::Display::fmt(self, f)
1391 }
1392}
1393
1394impl Add<Duration> for OffsetDateTime {
1395 type Output = Self;
1396
1397 /// # Panics
1398 ///
1399 /// This may panic if an overflow occurs.
1400 fn add(self, duration: Duration) -> Self::Output {
1401 self.checked_add(duration)
1402 .expect("resulting value is out of range")
1403 }
1404}
1405
1406impl Add<StdDuration> for OffsetDateTime {
1407 type Output = Self;
1408
1409 /// # Panics
1410 ///
1411 /// This may panic if an overflow occurs.
1412 fn add(self, duration: StdDuration) -> Self::Output {
1413 let (is_next_day, time) = self.time().adjusting_add_std(duration);
1414
1415 Self::new_in_offset(
1416 if is_next_day {
1417 (self.date() + duration)
1418 .next_day()
1419 .expect("resulting value is out of range")
1420 } else {
1421 self.date() + duration
1422 },
1423 time,
1424 self.offset,
1425 )
1426 }
1427}
1428
1429impl AddAssign<Duration> for OffsetDateTime {
1430 /// # Panics
1431 ///
1432 /// This may panic if an overflow occurs.
1433 fn add_assign(&mut self, rhs: Duration) {
1434 *self = *self + rhs;
1435 }
1436}
1437
1438impl AddAssign<StdDuration> for OffsetDateTime {
1439 /// # Panics
1440 ///
1441 /// This may panic if an overflow occurs.
1442 fn add_assign(&mut self, rhs: StdDuration) {
1443 *self = *self + rhs;
1444 }
1445}
1446
1447impl Sub<Duration> for OffsetDateTime {
1448 type Output = Self;
1449
1450 /// # Panics
1451 ///
1452 /// This may panic if an overflow occurs.
1453 fn sub(self, rhs: Duration) -> Self::Output {
1454 self.checked_sub(rhs)
1455 .expect("resulting value is out of range")
1456 }
1457}
1458
1459impl Sub<StdDuration> for OffsetDateTime {
1460 type Output = Self;
1461
1462 /// # Panics
1463 ///
1464 /// This may panic if an overflow occurs.
1465 fn sub(self, duration: StdDuration) -> Self::Output {
1466 let (is_previous_day, time) = self.time().adjusting_sub_std(duration);
1467
1468 Self::new_in_offset(
1469 if is_previous_day {
1470 (self.date() - duration)
1471 .previous_day()
1472 .expect("resulting value is out of range")
1473 } else {
1474 self.date() - duration
1475 },
1476 time,
1477 self.offset,
1478 )
1479 }
1480}
1481
1482impl SubAssign<Duration> for OffsetDateTime {
1483 /// # Panics
1484 ///
1485 /// This may panic if an overflow occurs.
1486 fn sub_assign(&mut self, rhs: Duration) {
1487 *self = *self - rhs;
1488 }
1489}
1490
1491impl SubAssign<StdDuration> for OffsetDateTime {
1492 /// # Panics
1493 ///
1494 /// This may panic if an overflow occurs.
1495 fn sub_assign(&mut self, rhs: StdDuration) {
1496 *self = *self - rhs;
1497 }
1498}
1499
1500impl Sub for OffsetDateTime {
1501 type Output = Duration;
1502
1503 /// # Panics
1504 ///
1505 /// This may panic if an overflow occurs.
1506 fn sub(self, rhs: Self) -> Self::Output {
1507 let base = self.date_time() - rhs.date_time();
1508 let adjustment = Duration::seconds(
1509 (self.offset.whole_seconds() - rhs.offset.whole_seconds()).extend::<i64>(),
1510 );
1511 base - adjustment
1512 }
1513}