time/primitive_date_time.rs
1//! The [`PrimitiveDateTime`] struct and its associated `impl`s.
2
3#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::cmp::Ordering;
6use core::fmt;
7use core::hash::{Hash, Hasher};
8use core::ops::{Add, AddAssign, Sub, SubAssign};
9use core::time::Duration as StdDuration;
10#[cfg(feature = "formatting")]
11use std::io;
12
13use powerfmt::ext::FormatterExt as _;
14use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
15
16#[cfg(feature = "formatting")]
17use crate::formatting::Formattable;
18use crate::internal_macros::{const_try, const_try_opt};
19#[cfg(feature = "parsing")]
20use crate::parsing::Parsable;
21use crate::{
22 Date, Duration, Month, OffsetDateTime, Time, UtcDateTime, UtcOffset, Weekday, error, util,
23};
24
25/// Combined date and time.
26#[derive(Clone, Copy, Eq)]
27#[cfg_attr(not(docsrs), repr(C))]
28pub struct PrimitiveDateTime {
29 // The order of this struct's fields matter! Do not reorder them.
30
31 // Little endian version
32 #[cfg(target_endian = "little")]
33 time: Time,
34 #[cfg(target_endian = "little")]
35 date: Date,
36
37 // Big endian version
38 #[cfg(target_endian = "big")]
39 date: Date,
40 #[cfg(target_endian = "big")]
41 time: Time,
42}
43
44impl Hash for PrimitiveDateTime {
45 #[inline]
46 fn hash<H>(&self, state: &mut H)
47 where
48 H: Hasher,
49 {
50 self.as_i128().hash(state);
51 }
52}
53
54impl PartialEq for PrimitiveDateTime {
55 #[inline]
56 fn eq(&self, other: &Self) -> bool {
57 self.as_i128().eq(&other.as_i128())
58 }
59}
60
61impl PartialOrd for PrimitiveDateTime {
62 #[inline]
63 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
64 Some(self.cmp(other))
65 }
66}
67
68impl Ord for PrimitiveDateTime {
69 #[inline]
70 fn cmp(&self, other: &Self) -> Ordering {
71 self.as_i128().cmp(&other.as_i128())
72 }
73}
74
75impl PrimitiveDateTime {
76 /// Provide a representation of `PrimitiveDateTime` as a `i128`. This value can be used for
77 /// equality, hashing, and ordering.
78 ///
79 /// **Note**: This value is explicitly signed, so do not cast this to or treat this as an
80 /// unsigned integer. Doing so will lead to incorrect results for values with differing
81 /// signs.
82 #[inline]
83 const fn as_i128(self) -> i128 {
84 let time = self.time.as_u64() as i128;
85 let date = self.date.as_i32() as i128;
86 (date << 64) | time
87 }
88
89 /// The smallest value that can be represented by `PrimitiveDateTime`.
90 ///
91 /// Depending on `large-dates` feature flag, value of this constant may vary.
92 ///
93 /// 1. With `large-dates` disabled it is equal to `-9999-01-01 00:00:00.0`
94 /// 2. With `large-dates` enabled it is equal to `-999999-01-01 00:00:00.0`
95 ///
96 /// ```rust
97 /// # use time::PrimitiveDateTime;
98 /// # use time_macros::datetime;
99 #[cfg_attr(
100 feature = "large-dates",
101 doc = "// Assuming `large-dates` feature is enabled."
102 )]
103 #[cfg_attr(
104 feature = "large-dates",
105 doc = "assert_eq!(PrimitiveDateTime::MIN, datetime!(-999999-01-01 0:00));"
106 )]
107 #[cfg_attr(
108 not(feature = "large-dates"),
109 doc = "// Assuming `large-dates` feature is disabled."
110 )]
111 #[cfg_attr(
112 not(feature = "large-dates"),
113 doc = "assert_eq!(PrimitiveDateTime::MIN, datetime!(-9999-01-01 0:00));"
114 )]
115 /// ```
116 pub const MIN: Self = Self {
117 date: Date::MIN,
118 time: Time::MIDNIGHT,
119 };
120
121 /// The largest value that can be represented by `PrimitiveDateTime`.
122 ///
123 /// Depending on `large-dates` feature flag, value of this constant may vary.
124 ///
125 /// 1. With `large-dates` disabled it is equal to `9999-12-31 23:59:59.999_999_999`
126 /// 2. With `large-dates` enabled it is equal to `999999-12-31 23:59:59.999_999_999`
127 ///
128 /// ```rust
129 /// # use time::PrimitiveDateTime;
130 /// # use time_macros::datetime;
131 #[cfg_attr(
132 feature = "large-dates",
133 doc = "// Assuming `large-dates` feature is enabled."
134 )]
135 #[cfg_attr(
136 feature = "large-dates",
137 doc = "assert_eq!(PrimitiveDateTime::MAX, datetime!(+999999-12-31 23:59:59.999_999_999));"
138 )]
139 #[cfg_attr(
140 not(feature = "large-dates"),
141 doc = "// Assuming `large-dates` feature is disabled."
142 )]
143 #[cfg_attr(
144 not(feature = "large-dates"),
145 doc = "assert_eq!(PrimitiveDateTime::MAX, datetime!(+9999-12-31 23:59:59.999_999_999));"
146 )]
147 /// ```
148 pub const MAX: Self = Self {
149 date: Date::MAX,
150 time: Time::MAX,
151 };
152
153 /// Create a new `PrimitiveDateTime` from the provided [`Date`] and [`Time`].
154 ///
155 /// ```rust
156 /// # use time::PrimitiveDateTime;
157 /// # use time_macros::{date, datetime, time};
158 /// assert_eq!(
159 /// PrimitiveDateTime::new(date!(2019-01-01), time!(0:00)),
160 /// datetime!(2019-01-01 0:00),
161 /// );
162 /// ```
163 #[inline]
164 pub const fn new(date: Date, time: Time) -> Self {
165 Self { date, time }
166 }
167
168 /// Get the [`Date`] component of the `PrimitiveDateTime`.
169 ///
170 /// ```rust
171 /// # use time_macros::{date, datetime};
172 /// assert_eq!(datetime!(2019-01-01 0:00).date(), date!(2019-01-01));
173 /// ```
174 #[inline]
175 pub const fn date(self) -> Date {
176 self.date
177 }
178
179 /// Get the [`Time`] component of the `PrimitiveDateTime`.
180 ///
181 /// ```rust
182 /// # use time_macros::{datetime, time};
183 /// assert_eq!(datetime!(2019-01-01 0:00).time(), time!(0:00));
184 /// ```
185 #[inline]
186 pub const fn time(self) -> Time {
187 self.time
188 }
189
190 /// Get the year of the date.
191 ///
192 /// ```rust
193 /// # use time_macros::datetime;
194 /// assert_eq!(datetime!(2019-01-01 0:00).year(), 2019);
195 /// assert_eq!(datetime!(2019-12-31 0:00).year(), 2019);
196 /// assert_eq!(datetime!(2020-01-01 0:00).year(), 2020);
197 /// ```
198 #[inline]
199 pub const fn year(self) -> i32 {
200 self.date().year()
201 }
202
203 /// Get the month of the date.
204 ///
205 /// ```rust
206 /// # use time::Month;
207 /// # use time_macros::datetime;
208 /// assert_eq!(datetime!(2019-01-01 0:00).month(), Month::January);
209 /// assert_eq!(datetime!(2019-12-31 0:00).month(), Month::December);
210 /// ```
211 #[inline]
212 pub const fn month(self) -> Month {
213 self.date().month()
214 }
215
216 /// Get the day of the date.
217 ///
218 /// The returned value will always be in the range `1..=31`.
219 ///
220 /// ```rust
221 /// # use time_macros::datetime;
222 /// assert_eq!(datetime!(2019-01-01 0:00).day(), 1);
223 /// assert_eq!(datetime!(2019-12-31 0:00).day(), 31);
224 /// ```
225 #[inline]
226 pub const fn day(self) -> u8 {
227 self.date().day()
228 }
229
230 /// Get the day of the year.
231 ///
232 /// The returned value will always be in the range `1..=366` (`1..=365` for common years).
233 ///
234 /// ```rust
235 /// # use time_macros::datetime;
236 /// assert_eq!(datetime!(2019-01-01 0:00).ordinal(), 1);
237 /// assert_eq!(datetime!(2019-12-31 0:00).ordinal(), 365);
238 /// ```
239 #[inline]
240 pub const fn ordinal(self) -> u16 {
241 self.date().ordinal()
242 }
243
244 /// Get the ISO week number.
245 ///
246 /// The returned value will always be in the range `1..=53`.
247 ///
248 /// ```rust
249 /// # use time_macros::datetime;
250 /// assert_eq!(datetime!(2019-01-01 0:00).iso_week(), 1);
251 /// assert_eq!(datetime!(2019-10-04 0:00).iso_week(), 40);
252 /// assert_eq!(datetime!(2020-01-01 0:00).iso_week(), 1);
253 /// assert_eq!(datetime!(2020-12-31 0:00).iso_week(), 53);
254 /// assert_eq!(datetime!(2021-01-01 0:00).iso_week(), 53);
255 /// ```
256 #[inline]
257 pub const fn iso_week(self) -> u8 {
258 self.date().iso_week()
259 }
260
261 /// Get the week number where week 1 begins on the first Sunday.
262 ///
263 /// The returned value will always be in the range `0..=53`.
264 ///
265 /// ```rust
266 /// # use time_macros::datetime;
267 /// assert_eq!(datetime!(2019-01-01 0:00).sunday_based_week(), 0);
268 /// assert_eq!(datetime!(2020-01-01 0:00).sunday_based_week(), 0);
269 /// assert_eq!(datetime!(2020-12-31 0:00).sunday_based_week(), 52);
270 /// assert_eq!(datetime!(2021-01-01 0:00).sunday_based_week(), 0);
271 /// ```
272 #[inline]
273 pub const fn sunday_based_week(self) -> u8 {
274 self.date().sunday_based_week()
275 }
276
277 /// Get the week number where week 1 begins on the first Monday.
278 ///
279 /// The returned value will always be in the range `0..=53`.
280 ///
281 /// ```rust
282 /// # use time_macros::datetime;
283 /// assert_eq!(datetime!(2019-01-01 0:00).monday_based_week(), 0);
284 /// assert_eq!(datetime!(2020-01-01 0:00).monday_based_week(), 0);
285 /// assert_eq!(datetime!(2020-12-31 0:00).monday_based_week(), 52);
286 /// assert_eq!(datetime!(2021-01-01 0:00).monday_based_week(), 0);
287 /// ```
288 #[inline]
289 pub const fn monday_based_week(self) -> u8 {
290 self.date().monday_based_week()
291 }
292
293 /// Get the year, month, and day.
294 ///
295 /// ```rust
296 /// # use time::Month;
297 /// # use time_macros::datetime;
298 /// assert_eq!(
299 /// datetime!(2019-01-01 0:00).to_calendar_date(),
300 /// (2019, Month::January, 1)
301 /// );
302 /// ```
303 #[inline]
304 pub const fn to_calendar_date(self) -> (i32, Month, u8) {
305 self.date().to_calendar_date()
306 }
307
308 /// Get the year and ordinal day number.
309 ///
310 /// ```rust
311 /// # use time_macros::datetime;
312 /// assert_eq!(datetime!(2019-01-01 0:00).to_ordinal_date(), (2019, 1));
313 /// ```
314 #[inline]
315 pub const fn to_ordinal_date(self) -> (i32, u16) {
316 self.date().to_ordinal_date()
317 }
318
319 /// Get the ISO 8601 year, week number, and weekday.
320 ///
321 /// ```rust
322 /// # use time::Weekday::*;
323 /// # use time_macros::datetime;
324 /// assert_eq!(
325 /// datetime!(2019-01-01 0:00).to_iso_week_date(),
326 /// (2019, 1, Tuesday)
327 /// );
328 /// assert_eq!(
329 /// datetime!(2019-10-04 0:00).to_iso_week_date(),
330 /// (2019, 40, Friday)
331 /// );
332 /// assert_eq!(
333 /// datetime!(2020-01-01 0:00).to_iso_week_date(),
334 /// (2020, 1, Wednesday)
335 /// );
336 /// assert_eq!(
337 /// datetime!(2020-12-31 0:00).to_iso_week_date(),
338 /// (2020, 53, Thursday)
339 /// );
340 /// assert_eq!(
341 /// datetime!(2021-01-01 0:00).to_iso_week_date(),
342 /// (2020, 53, Friday)
343 /// );
344 /// ```
345 #[inline]
346 pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
347 self.date().to_iso_week_date()
348 }
349
350 /// Get the weekday.
351 ///
352 /// ```rust
353 /// # use time::Weekday::*;
354 /// # use time_macros::datetime;
355 /// assert_eq!(datetime!(2019-01-01 0:00).weekday(), Tuesday);
356 /// assert_eq!(datetime!(2019-02-01 0:00).weekday(), Friday);
357 /// assert_eq!(datetime!(2019-03-01 0:00).weekday(), Friday);
358 /// assert_eq!(datetime!(2019-04-01 0:00).weekday(), Monday);
359 /// assert_eq!(datetime!(2019-05-01 0:00).weekday(), Wednesday);
360 /// assert_eq!(datetime!(2019-06-01 0:00).weekday(), Saturday);
361 /// assert_eq!(datetime!(2019-07-01 0:00).weekday(), Monday);
362 /// assert_eq!(datetime!(2019-08-01 0:00).weekday(), Thursday);
363 /// assert_eq!(datetime!(2019-09-01 0:00).weekday(), Sunday);
364 /// assert_eq!(datetime!(2019-10-01 0:00).weekday(), Tuesday);
365 /// assert_eq!(datetime!(2019-11-01 0:00).weekday(), Friday);
366 /// assert_eq!(datetime!(2019-12-01 0:00).weekday(), Sunday);
367 /// ```
368 #[inline]
369 pub const fn weekday(self) -> Weekday {
370 self.date().weekday()
371 }
372
373 /// Get the Julian day for the date. The time is not taken into account for this calculation.
374 ///
375 /// ```rust
376 /// # use time_macros::datetime;
377 /// assert_eq!(datetime!(-4713-11-24 0:00).to_julian_day(), 0);
378 /// assert_eq!(datetime!(2000-01-01 0:00).to_julian_day(), 2_451_545);
379 /// assert_eq!(datetime!(2019-01-01 0:00).to_julian_day(), 2_458_485);
380 /// assert_eq!(datetime!(2019-12-31 0:00).to_julian_day(), 2_458_849);
381 /// ```
382 #[inline]
383 pub const fn to_julian_day(self) -> i32 {
384 self.date().to_julian_day()
385 }
386
387 /// Get the clock hour, minute, and second.
388 ///
389 /// ```rust
390 /// # use time_macros::datetime;
391 /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms(), (0, 0, 0));
392 /// assert_eq!(datetime!(2020-01-01 23:59:59).as_hms(), (23, 59, 59));
393 /// ```
394 #[inline]
395 pub const fn as_hms(self) -> (u8, u8, u8) {
396 self.time().as_hms()
397 }
398
399 /// Get the clock hour, minute, second, and millisecond.
400 ///
401 /// ```rust
402 /// # use time_macros::datetime;
403 /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_milli(), (0, 0, 0, 0));
404 /// assert_eq!(
405 /// datetime!(2020-01-01 23:59:59.999).as_hms_milli(),
406 /// (23, 59, 59, 999)
407 /// );
408 /// ```
409 #[inline]
410 pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
411 self.time().as_hms_milli()
412 }
413
414 /// Get the clock hour, minute, second, and microsecond.
415 ///
416 /// ```rust
417 /// # use time_macros::datetime;
418 /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_micro(), (0, 0, 0, 0));
419 /// assert_eq!(
420 /// datetime!(2020-01-01 23:59:59.999_999).as_hms_micro(),
421 /// (23, 59, 59, 999_999)
422 /// );
423 /// ```
424 #[inline]
425 pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
426 self.time().as_hms_micro()
427 }
428
429 /// Get the clock hour, minute, second, and nanosecond.
430 ///
431 /// ```rust
432 /// # use time_macros::datetime;
433 /// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_nano(), (0, 0, 0, 0));
434 /// assert_eq!(
435 /// datetime!(2020-01-01 23:59:59.999_999_999).as_hms_nano(),
436 /// (23, 59, 59, 999_999_999)
437 /// );
438 /// ```
439 #[inline]
440 pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
441 self.time().as_hms_nano()
442 }
443
444 /// Get the clock hour.
445 ///
446 /// The returned value will always be in the range `0..24`.
447 ///
448 /// ```rust
449 /// # use time_macros::datetime;
450 /// assert_eq!(datetime!(2019-01-01 0:00).hour(), 0);
451 /// assert_eq!(datetime!(2019-01-01 23:59:59).hour(), 23);
452 /// ```
453 #[inline]
454 pub const fn hour(self) -> u8 {
455 self.time().hour()
456 }
457
458 /// Get the minute within the hour.
459 ///
460 /// The returned value will always be in the range `0..60`.
461 ///
462 /// ```rust
463 /// # use time_macros::datetime;
464 /// assert_eq!(datetime!(2019-01-01 0:00).minute(), 0);
465 /// assert_eq!(datetime!(2019-01-01 23:59:59).minute(), 59);
466 /// ```
467 #[inline]
468 pub const fn minute(self) -> u8 {
469 self.time().minute()
470 }
471
472 /// Get the second within the minute.
473 ///
474 /// The returned value will always be in the range `0..60`.
475 ///
476 /// ```rust
477 /// # use time_macros::datetime;
478 /// assert_eq!(datetime!(2019-01-01 0:00).second(), 0);
479 /// assert_eq!(datetime!(2019-01-01 23:59:59).second(), 59);
480 /// ```
481 #[inline]
482 pub const fn second(self) -> u8 {
483 self.time().second()
484 }
485
486 /// Get the milliseconds within the second.
487 ///
488 /// The returned value will always be in the range `0..1_000`.
489 ///
490 /// ```rust
491 /// # use time_macros::datetime;
492 /// assert_eq!(datetime!(2019-01-01 0:00).millisecond(), 0);
493 /// assert_eq!(datetime!(2019-01-01 23:59:59.999).millisecond(), 999);
494 /// ```
495 #[inline]
496 pub const fn millisecond(self) -> u16 {
497 self.time().millisecond()
498 }
499
500 /// Get the microseconds within the second.
501 ///
502 /// The returned value will always be in the range `0..1_000_000`.
503 ///
504 /// ```rust
505 /// # use time_macros::datetime;
506 /// assert_eq!(datetime!(2019-01-01 0:00).microsecond(), 0);
507 /// assert_eq!(
508 /// datetime!(2019-01-01 23:59:59.999_999).microsecond(),
509 /// 999_999
510 /// );
511 /// ```
512 #[inline]
513 pub const fn microsecond(self) -> u32 {
514 self.time().microsecond()
515 }
516
517 /// Get the nanoseconds within the second.
518 ///
519 /// The returned value will always be in the range `0..1_000_000_000`.
520 ///
521 /// ```rust
522 /// # use time_macros::datetime;
523 /// assert_eq!(datetime!(2019-01-01 0:00).nanosecond(), 0);
524 /// assert_eq!(
525 /// datetime!(2019-01-01 23:59:59.999_999_999).nanosecond(),
526 /// 999_999_999,
527 /// );
528 /// ```
529 #[inline]
530 pub const fn nanosecond(self) -> u32 {
531 self.time().nanosecond()
532 }
533
534 /// Assuming that the existing `PrimitiveDateTime` represents a moment in the provided
535 /// [`UtcOffset`], return an [`OffsetDateTime`].
536 ///
537 /// ```rust
538 /// # use time_macros::{datetime, offset};
539 /// assert_eq!(
540 /// datetime!(2019-01-01 0:00)
541 /// .assume_offset(offset!(UTC))
542 /// .unix_timestamp(),
543 /// 1_546_300_800,
544 /// );
545 /// assert_eq!(
546 /// datetime!(2019-01-01 0:00)
547 /// .assume_offset(offset!(-1))
548 /// .unix_timestamp(),
549 /// 1_546_304_400,
550 /// );
551 /// ```
552 #[inline]
553 pub const fn assume_offset(self, offset: UtcOffset) -> OffsetDateTime {
554 OffsetDateTime::new_in_offset(self.date, self.time, offset)
555 }
556
557 /// Assuming that the existing `PrimitiveDateTime` represents a moment in UTC, return an
558 /// [`OffsetDateTime`].
559 ///
560 /// ```rust
561 /// # use time_macros::datetime;
562 /// assert_eq!(
563 /// datetime!(2019-01-01 0:00).assume_utc().unix_timestamp(),
564 /// 1_546_300_800,
565 /// );
566 /// ```
567 ///
568 /// **Note**: You may want a [`UtcDateTime`] instead, which can be obtained with the
569 /// [`PrimitiveDateTime::as_utc`] method.
570 #[inline]
571 pub const fn assume_utc(self) -> OffsetDateTime {
572 self.assume_offset(UtcOffset::UTC)
573 }
574
575 /// Assuming that the existing `PrimitiveDateTime` represents a moment in UTC, return a
576 /// [`UtcDateTime`].
577 ///
578 /// ```rust
579 /// # use time_macros::datetime;
580 /// assert_eq!(
581 /// datetime!(2019-01-01 0:00).as_utc().unix_timestamp(),
582 /// 1_546_300_800,
583 /// );
584 /// ```
585 #[inline]
586 pub const fn as_utc(self) -> UtcDateTime {
587 UtcDateTime::from_primitive(self)
588 }
589
590 /// Computes `self + duration`, returning `None` if an overflow occurred.
591 ///
592 /// ```
593 /// # use time::{Date, ext::NumericalDuration};
594 /// # use time_macros::datetime;
595 /// let datetime = Date::MIN.midnight();
596 /// assert_eq!(datetime.checked_add((-2).days()), None);
597 ///
598 /// let datetime = Date::MAX.midnight();
599 /// assert_eq!(datetime.checked_add(1.days()), None);
600 ///
601 /// assert_eq!(
602 /// datetime!(2019-11-25 15:30).checked_add(27.hours()),
603 /// Some(datetime!(2019-11-26 18:30))
604 /// );
605 /// ```
606 #[inline]
607 pub const fn checked_add(self, duration: Duration) -> Option<Self> {
608 let (date_adjustment, time) = self.time.adjusting_add(duration);
609 let date = const_try_opt!(self.date.checked_add(duration));
610
611 Some(Self {
612 date: match date_adjustment {
613 util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
614 util::DateAdjustment::Next => const_try_opt!(date.next_day()),
615 util::DateAdjustment::None => date,
616 },
617 time,
618 })
619 }
620
621 /// Computes `self - duration`, returning `None` if an overflow occurred.
622 ///
623 /// ```
624 /// # use time::{Date, ext::NumericalDuration};
625 /// # use time_macros::datetime;
626 /// let datetime = Date::MIN.midnight();
627 /// assert_eq!(datetime.checked_sub(2.days()), None);
628 ///
629 /// let datetime = Date::MAX.midnight();
630 /// assert_eq!(datetime.checked_sub((-1).days()), None);
631 ///
632 /// assert_eq!(
633 /// datetime!(2019-11-25 15:30).checked_sub(27.hours()),
634 /// Some(datetime!(2019-11-24 12:30))
635 /// );
636 /// ```
637 #[inline]
638 pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
639 let (date_adjustment, time) = self.time.adjusting_sub(duration);
640 let date = const_try_opt!(self.date.checked_sub(duration));
641
642 Some(Self {
643 date: match date_adjustment {
644 util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
645 util::DateAdjustment::Next => const_try_opt!(date.next_day()),
646 util::DateAdjustment::None => date,
647 },
648 time,
649 })
650 }
651
652 /// Computes `self + duration`, saturating value on overflow.
653 ///
654 /// ```
655 /// # use time::{PrimitiveDateTime, ext::NumericalDuration};
656 /// # use time_macros::datetime;
657 /// assert_eq!(
658 /// PrimitiveDateTime::MIN.saturating_add((-2).days()),
659 /// PrimitiveDateTime::MIN
660 /// );
661 ///
662 /// assert_eq!(
663 /// PrimitiveDateTime::MAX.saturating_add(2.days()),
664 /// PrimitiveDateTime::MAX
665 /// );
666 ///
667 /// assert_eq!(
668 /// datetime!(2019-11-25 15:30).saturating_add(27.hours()),
669 /// datetime!(2019-11-26 18:30)
670 /// );
671 /// ```
672 #[inline]
673 pub const fn saturating_add(self, duration: Duration) -> Self {
674 if let Some(datetime) = self.checked_add(duration) {
675 datetime
676 } else if duration.is_negative() {
677 Self::MIN
678 } else {
679 Self::MAX
680 }
681 }
682
683 /// Computes `self - duration`, saturating value on overflow.
684 ///
685 /// ```
686 /// # use time::{PrimitiveDateTime, ext::NumericalDuration};
687 /// # use time_macros::datetime;
688 /// assert_eq!(
689 /// PrimitiveDateTime::MIN.saturating_sub(2.days()),
690 /// PrimitiveDateTime::MIN
691 /// );
692 ///
693 /// assert_eq!(
694 /// PrimitiveDateTime::MAX.saturating_sub((-2).days()),
695 /// PrimitiveDateTime::MAX
696 /// );
697 ///
698 /// assert_eq!(
699 /// datetime!(2019-11-25 15:30).saturating_sub(27.hours()),
700 /// datetime!(2019-11-24 12:30)
701 /// );
702 /// ```
703 #[inline]
704 pub const fn saturating_sub(self, duration: Duration) -> Self {
705 if let Some(datetime) = self.checked_sub(duration) {
706 datetime
707 } else if duration.is_negative() {
708 Self::MAX
709 } else {
710 Self::MIN
711 }
712 }
713}
714
715/// Methods that replace part of the `PrimitiveDateTime`.
716impl PrimitiveDateTime {
717 /// Replace the time, preserving the date.
718 ///
719 /// ```rust
720 /// # use time_macros::{datetime, time};
721 /// assert_eq!(
722 /// datetime!(2020-01-01 17:00).replace_time(time!(5:00)),
723 /// datetime!(2020-01-01 5:00)
724 /// );
725 /// ```
726 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
727 #[inline]
728 pub const fn replace_time(self, time: Time) -> Self {
729 Self {
730 date: self.date,
731 time,
732 }
733 }
734
735 /// Replace the date, preserving the time.
736 ///
737 /// ```rust
738 /// # use time_macros::{datetime, date};
739 /// assert_eq!(
740 /// datetime!(2020-01-01 12:00).replace_date(date!(2020-01-30)),
741 /// datetime!(2020-01-30 12:00)
742 /// );
743 /// ```
744 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
745 #[inline]
746 pub const fn replace_date(self, date: Date) -> Self {
747 Self {
748 date,
749 time: self.time,
750 }
751 }
752
753 /// Replace the year. The month and day will be unchanged.
754 ///
755 /// ```rust
756 /// # use time_macros::datetime;
757 /// assert_eq!(
758 /// datetime!(2022-02-18 12:00).replace_year(2019),
759 /// Ok(datetime!(2019-02-18 12:00))
760 /// );
761 /// assert!(datetime!(2022-02-18 12:00).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
762 /// assert!(datetime!(2022-02-18 12:00).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
763 /// ```
764 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
765 #[inline]
766 pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
767 Ok(Self {
768 date: const_try!(self.date.replace_year(year)),
769 time: self.time,
770 })
771 }
772
773 /// Replace the month of the year.
774 ///
775 /// ```rust
776 /// # use time_macros::datetime;
777 /// # use time::Month;
778 /// assert_eq!(
779 /// datetime!(2022-02-18 12:00).replace_month(Month::January),
780 /// Ok(datetime!(2022-01-18 12:00))
781 /// );
782 /// assert!(datetime!(2022-01-30 12:00).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
783 /// ```
784 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
785 #[inline]
786 pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
787 Ok(Self {
788 date: const_try!(self.date.replace_month(month)),
789 time: self.time,
790 })
791 }
792
793 /// Replace the day of the month.
794 ///
795 /// ```rust
796 /// # use time_macros::datetime;
797 /// assert_eq!(
798 /// datetime!(2022-02-18 12:00).replace_day(1),
799 /// Ok(datetime!(2022-02-01 12:00))
800 /// );
801 /// assert!(datetime!(2022-02-18 12:00).replace_day(0).is_err()); // 00 isn't a valid day
802 /// assert!(datetime!(2022-02-18 12:00).replace_day(30).is_err()); // 30 isn't a valid day in February
803 /// ```
804 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
805 #[inline]
806 pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
807 Ok(Self {
808 date: const_try!(self.date.replace_day(day)),
809 time: self.time,
810 })
811 }
812
813 /// Replace the day of the year.
814 ///
815 /// ```rust
816 /// # use time_macros::datetime;
817 /// assert_eq!(datetime!(2022-049 12:00).replace_ordinal(1), Ok(datetime!(2022-001 12:00)));
818 /// assert!(datetime!(2022-049 12:00).replace_ordinal(0).is_err()); // 0 isn't a valid ordinal
819 /// assert!(datetime!(2022-049 12:00).replace_ordinal(366).is_err()); // 2022 isn't a leap year
820 /// ```
821 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
822 #[inline]
823 pub const fn replace_ordinal(self, ordinal: u16) -> Result<Self, error::ComponentRange> {
824 Ok(Self {
825 date: const_try!(self.date.replace_ordinal(ordinal)),
826 time: self.time,
827 })
828 }
829
830 /// Truncate to the start of the day, setting the time to midnight.
831 ///
832 /// ```rust
833 /// # use time_macros::datetime;
834 /// assert_eq!(
835 /// datetime!(2022-02-18 15:30:45.123_456_789).truncate_to_day(),
836 /// datetime!(2022-02-18 0:00)
837 /// );
838 /// ```
839 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
840 #[inline]
841 pub const fn truncate_to_day(self) -> Self {
842 self.replace_time(Time::MIDNIGHT)
843 }
844
845 /// Replace the clock hour.
846 ///
847 /// ```rust
848 /// # use time_macros::datetime;
849 /// assert_eq!(
850 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_hour(7),
851 /// Ok(datetime!(2022-02-18 07:02:03.004_005_006))
852 /// );
853 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
854 /// ```
855 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
856 #[inline]
857 pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
858 Ok(Self {
859 date: self.date,
860 time: const_try!(self.time.replace_hour(hour)),
861 })
862 }
863
864 /// Truncate to the hour, setting the minute, second, and subsecond components to zero.
865 ///
866 /// ```rust
867 /// # use time_macros::datetime;
868 /// assert_eq!(
869 /// datetime!(2022-02-18 15:30:45.123_456_789).truncate_to_hour(),
870 /// datetime!(2022-02-18 15:00)
871 /// );
872 /// ```
873 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
874 #[inline]
875 pub const fn truncate_to_hour(self) -> Self {
876 self.replace_time(self.time.truncate_to_hour())
877 }
878
879 /// Replace the minutes within the hour.
880 ///
881 /// ```rust
882 /// # use time_macros::datetime;
883 /// assert_eq!(
884 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_minute(7),
885 /// Ok(datetime!(2022-02-18 01:07:03.004_005_006))
886 /// );
887 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
888 /// ```
889 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
890 #[inline]
891 pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
892 Ok(Self {
893 date: self.date,
894 time: const_try!(self.time.replace_minute(minute)),
895 })
896 }
897
898 /// Truncate to the minute, setting the second and subsecond components to zero.
899 ///
900 /// ```rust
901 /// # use time_macros::datetime;
902 /// assert_eq!(
903 /// datetime!(2022-02-18 15:30:45.123_456_789).truncate_to_minute(),
904 /// datetime!(2022-02-18 15:30)
905 /// );
906 /// ```
907 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
908 #[inline]
909 pub const fn truncate_to_minute(self) -> Self {
910 self.replace_time(self.time.truncate_to_minute())
911 }
912
913 /// Replace the seconds within the minute.
914 ///
915 /// ```rust
916 /// # use time_macros::datetime;
917 /// assert_eq!(
918 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_second(7),
919 /// Ok(datetime!(2022-02-18 01:02:07.004_005_006))
920 /// );
921 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
922 /// ```
923 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
924 #[inline]
925 pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
926 Ok(Self {
927 date: self.date,
928 time: const_try!(self.time.replace_second(second)),
929 })
930 }
931
932 /// Truncate to the second, setting the subsecond components to zero.
933 ///
934 /// ```rust
935 /// # use time_macros::datetime;
936 /// assert_eq!(
937 /// datetime!(2022-02-18 15:30:45.123_456_789).truncate_to_second(),
938 /// datetime!(2022-02-18 15:30:45)
939 /// );
940 /// ```
941 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
942 #[inline]
943 pub const fn truncate_to_second(self) -> Self {
944 self.replace_time(self.time.truncate_to_second())
945 }
946
947 /// Replace the milliseconds within the second.
948 ///
949 /// ```rust
950 /// # use time_macros::datetime;
951 /// assert_eq!(
952 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_millisecond(7),
953 /// Ok(datetime!(2022-02-18 01:02:03.007))
954 /// );
955 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
956 /// ```
957 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
958 #[inline]
959 pub const fn replace_millisecond(
960 self,
961 millisecond: u16,
962 ) -> Result<Self, error::ComponentRange> {
963 Ok(Self {
964 date: self.date,
965 time: const_try!(self.time.replace_millisecond(millisecond)),
966 })
967 }
968
969 /// Truncate to the millisecond, setting the microsecond and nanosecond components to zero.
970 ///
971 /// ```rust
972 /// # use time_macros::datetime;
973 /// assert_eq!(
974 /// datetime!(2022-02-18 15:30:45.123_456_789).truncate_to_millisecond(),
975 /// datetime!(2022-02-18 15:30:45.123)
976 /// );
977 /// ```
978 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
979 #[inline]
980 pub const fn truncate_to_millisecond(self) -> Self {
981 self.replace_time(self.time.truncate_to_millisecond())
982 }
983
984 /// Replace the microseconds within the second.
985 ///
986 /// ```rust
987 /// # use time_macros::datetime;
988 /// assert_eq!(
989 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_microsecond(7_008),
990 /// Ok(datetime!(2022-02-18 01:02:03.007_008))
991 /// );
992 /// assert!(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
993 /// ```
994 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
995 #[inline]
996 pub const fn replace_microsecond(
997 self,
998 microsecond: u32,
999 ) -> Result<Self, error::ComponentRange> {
1000 Ok(Self {
1001 date: self.date,
1002 time: const_try!(self.time.replace_microsecond(microsecond)),
1003 })
1004 }
1005
1006 /// Truncate to the microsecond, setting the nanosecond component to zero.
1007 ///
1008 /// ```rust
1009 /// # use time_macros::datetime;
1010 /// assert_eq!(
1011 /// datetime!(2022-02-18 15:30:45.123_456_789).truncate_to_microsecond(),
1012 /// datetime!(2022-02-18 15:30:45.123_456)
1013 /// );
1014 /// ```
1015 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
1016 #[inline]
1017 pub const fn truncate_to_microsecond(self) -> Self {
1018 self.replace_time(self.time.truncate_to_microsecond())
1019 }
1020
1021 /// Replace the nanoseconds within the second.
1022 ///
1023 /// ```rust
1024 /// # use time_macros::datetime;
1025 /// assert_eq!(
1026 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_nanosecond(7_008_009),
1027 /// Ok(datetime!(2022-02-18 01:02:03.007_008_009))
1028 /// );
1029 /// assert!(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
1030 /// ```
1031 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
1032 #[inline]
1033 pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
1034 Ok(Self {
1035 date: self.date,
1036 time: const_try!(self.time.replace_nanosecond(nanosecond)),
1037 })
1038 }
1039}
1040
1041#[cfg(feature = "formatting")]
1042impl PrimitiveDateTime {
1043 /// Format the `PrimitiveDateTime` using the provided [format
1044 /// description](crate::format_description).
1045 #[inline]
1046 pub fn format_into(
1047 self,
1048 output: &mut (impl io::Write + ?Sized),
1049 format: &(impl Formattable + ?Sized),
1050 ) -> Result<usize, error::Format> {
1051 format.format_into(output, Some(self.date), Some(self.time), None)
1052 }
1053
1054 /// Format the `PrimitiveDateTime` using the provided [format
1055 /// description](crate::format_description).
1056 ///
1057 /// ```rust
1058 /// # use time::format_description;
1059 /// # use time_macros::datetime;
1060 /// let format = format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")?;
1061 /// assert_eq!(
1062 /// datetime!(2020-01-02 03:04:05).format(&format)?,
1063 /// "2020-01-02 03:04:05"
1064 /// );
1065 /// # Ok::<_, time::Error>(())
1066 /// ```
1067 #[inline]
1068 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
1069 format.format(Some(self.date), Some(self.time), None)
1070 }
1071}
1072
1073#[cfg(feature = "parsing")]
1074impl PrimitiveDateTime {
1075 /// Parse a `PrimitiveDateTime` from the input using the provided [format
1076 /// description](crate::format_description).
1077 ///
1078 /// ```rust
1079 /// # use time::PrimitiveDateTime;
1080 /// # use time_macros::{datetime, format_description};
1081 /// let format = format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
1082 /// assert_eq!(
1083 /// PrimitiveDateTime::parse("2020-01-02 03:04:05", &format)?,
1084 /// datetime!(2020-01-02 03:04:05)
1085 /// );
1086 /// # Ok::<_, time::Error>(())
1087 /// ```
1088 #[inline]
1089 pub fn parse(
1090 input: &str,
1091 description: &(impl Parsable + ?Sized),
1092 ) -> Result<Self, error::Parse> {
1093 description.parse_primitive_date_time(input.as_bytes())
1094 }
1095}
1096
1097impl SmartDisplay for PrimitiveDateTime {
1098 type Metadata = ();
1099
1100 #[inline]
1101 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
1102 let width = smart_display::padded_width_of!(self.date, " ", self.time);
1103 Metadata::new(width, self, ())
1104 }
1105
1106 #[inline]
1107 fn fmt_with_metadata(
1108 &self,
1109 f: &mut fmt::Formatter<'_>,
1110 metadata: Metadata<Self>,
1111 ) -> fmt::Result {
1112 f.pad_with_width(
1113 metadata.unpadded_width(),
1114 format_args!("{} {}", self.date, self.time),
1115 )
1116 }
1117}
1118
1119impl fmt::Display for PrimitiveDateTime {
1120 #[inline]
1121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1122 SmartDisplay::fmt(self, f)
1123 }
1124}
1125
1126impl fmt::Debug for PrimitiveDateTime {
1127 #[inline]
1128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1129 fmt::Display::fmt(self, f)
1130 }
1131}
1132
1133impl Add<Duration> for PrimitiveDateTime {
1134 type Output = Self;
1135
1136 /// # Panics
1137 ///
1138 /// This may panic if an overflow occurs.
1139 #[inline]
1140 #[track_caller]
1141 fn add(self, duration: Duration) -> Self::Output {
1142 self.checked_add(duration)
1143 .expect("resulting value is out of range")
1144 }
1145}
1146
1147impl Add<StdDuration> for PrimitiveDateTime {
1148 type Output = Self;
1149
1150 /// # Panics
1151 ///
1152 /// This may panic if an overflow occurs.
1153 #[inline]
1154 #[track_caller]
1155 fn add(self, duration: StdDuration) -> Self::Output {
1156 let (is_next_day, time) = self.time.adjusting_add_std(duration);
1157
1158 Self {
1159 date: if is_next_day {
1160 (self.date + duration)
1161 .next_day()
1162 .expect("resulting value is out of range")
1163 } else {
1164 self.date + duration
1165 },
1166 time,
1167 }
1168 }
1169}
1170
1171impl AddAssign<Duration> for PrimitiveDateTime {
1172 /// # Panics
1173 ///
1174 /// This may panic if an overflow occurs.
1175 #[inline]
1176 #[track_caller]
1177 fn add_assign(&mut self, duration: Duration) {
1178 *self = *self + duration;
1179 }
1180}
1181
1182impl AddAssign<StdDuration> for PrimitiveDateTime {
1183 /// # Panics
1184 ///
1185 /// This may panic if an overflow occurs.
1186 #[inline]
1187 #[track_caller]
1188 fn add_assign(&mut self, duration: StdDuration) {
1189 *self = *self + duration;
1190 }
1191}
1192
1193impl Sub<Duration> for PrimitiveDateTime {
1194 type Output = Self;
1195
1196 /// # Panics
1197 ///
1198 /// This may panic if an overflow occurs.
1199 #[inline]
1200 #[track_caller]
1201 fn sub(self, duration: Duration) -> Self::Output {
1202 self.checked_sub(duration)
1203 .expect("resulting value is out of range")
1204 }
1205}
1206
1207impl Sub<StdDuration> for PrimitiveDateTime {
1208 type Output = Self;
1209
1210 /// # Panics
1211 ///
1212 /// This may panic if an overflow occurs.
1213 #[inline]
1214 #[track_caller]
1215 fn sub(self, duration: StdDuration) -> Self::Output {
1216 let (is_previous_day, time) = self.time.adjusting_sub_std(duration);
1217
1218 Self {
1219 date: if is_previous_day {
1220 (self.date - duration)
1221 .previous_day()
1222 .expect("resulting value is out of range")
1223 } else {
1224 self.date - duration
1225 },
1226 time,
1227 }
1228 }
1229}
1230
1231impl SubAssign<Duration> for PrimitiveDateTime {
1232 /// # Panics
1233 ///
1234 /// This may panic if an overflow occurs.
1235 #[inline]
1236 #[track_caller]
1237 fn sub_assign(&mut self, duration: Duration) {
1238 *self = *self - duration;
1239 }
1240}
1241
1242impl SubAssign<StdDuration> for PrimitiveDateTime {
1243 /// # Panics
1244 ///
1245 /// This may panic if an overflow occurs.
1246 #[inline]
1247 #[track_caller]
1248 fn sub_assign(&mut self, duration: StdDuration) {
1249 *self = *self - duration;
1250 }
1251}
1252
1253impl Sub for PrimitiveDateTime {
1254 type Output = Duration;
1255
1256 /// # Panics
1257 ///
1258 /// This may panic if an overflow occurs.
1259 #[inline]
1260 #[track_caller]
1261 fn sub(self, rhs: Self) -> Self::Output {
1262 (self.date - rhs.date) + (self.time - rhs.time)
1263 }
1264}