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