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