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_i128().hash(state);
48 }
49}
50
51impl PartialEq for PrimitiveDateTime {
52 #[inline]
53 fn eq(&self, other: &Self) -> bool {
54 self.as_i128().eq(&other.as_i128())
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_i128().cmp(&other.as_i128())
69 }
70}
71
72impl PrimitiveDateTime {
73 /// Provide a representation of `PrimitiveDateTime` as a `i128`. This value can be used for
74 /// equality, hashing, and ordering.
75 ///
76 /// **Note**: This value is explicitly signed, so do not cast this to or treat this as an
77 /// unsigned integer. Doing so will lead to incorrect results for values with differing
78 /// signs.
79 #[inline]
80 const fn as_i128(self) -> i128 {
81 let time = self.time.as_u64() as i128;
82 let date = self.date.as_i32() as i128;
83 (date << 64) | time
84 }
85
86 /// The smallest value that can be represented by `PrimitiveDateTime`.
87 ///
88 /// Depending on `large-dates` feature flag, value of this constant may vary.
89 ///
90 /// 1. With `large-dates` disabled it is equal to `-9999-01-01 00:00:00.0`
91 /// 2. With `large-dates` enabled it is equal to `-999999-01-01 00:00:00.0`
92 ///
93 /// ```rust
94 /// # use time::PrimitiveDateTime;
95 /// # use time_macros::datetime;
96 #[cfg_attr(
97 feature = "large-dates",
98 doc = "// Assuming `large-dates` feature is enabled."
99 )]
100 #[cfg_attr(
101 feature = "large-dates",
102 doc = "assert_eq!(PrimitiveDateTime::MIN, datetime!(-999999-01-01 0:00));"
103 )]
104 #[cfg_attr(
105 not(feature = "large-dates"),
106 doc = "// Assuming `large-dates` feature is disabled."
107 )]
108 #[cfg_attr(
109 not(feature = "large-dates"),
110 doc = "assert_eq!(PrimitiveDateTime::MIN, datetime!(-9999-01-01 0:00));"
111 )]
112 /// ```
113 pub const MIN: Self = Self {
114 date: Date::MIN,
115 time: Time::MIDNIGHT,
116 };
117
118 /// The largest value that can be represented by `PrimitiveDateTime`.
119 ///
120 /// Depending on `large-dates` feature flag, value of this constant may vary.
121 ///
122 /// 1. With `large-dates` disabled it is equal to `9999-12-31 23:59:59.999_999_999`
123 /// 2. With `large-dates` enabled it is equal to `999999-12-31 23:59:59.999_999_999`
124 ///
125 /// ```rust
126 /// # use time::PrimitiveDateTime;
127 /// # use time_macros::datetime;
128 #[cfg_attr(
129 feature = "large-dates",
130 doc = "// Assuming `large-dates` feature is enabled."
131 )]
132 #[cfg_attr(
133 feature = "large-dates",
134 doc = "assert_eq!(PrimitiveDateTime::MAX, datetime!(+999999-12-31 23:59:59.999_999_999));"
135 )]
136 #[cfg_attr(
137 not(feature = "large-dates"),
138 doc = "// Assuming `large-dates` feature is disabled."
139 )]
140 #[cfg_attr(
141 not(feature = "large-dates"),
142 doc = "assert_eq!(PrimitiveDateTime::MAX, datetime!(+9999-12-31 23:59:59.999_999_999));"
143 )]
144 /// ```
145 pub const MAX: Self = Self {
146 date: Date::MAX,
147 time: Time::MAX,
148 };
149
150 /// Create a new `PrimitiveDateTime` from the provided [`Date`] and [`Time`].
151 ///
152 /// ```rust
153 /// # use time::PrimitiveDateTime;
154 /// # use time_macros::{date, datetime, time};
155 /// assert_eq!(
156 /// PrimitiveDateTime::new(date!(2019-01-01), time!(0:00)),
157 /// datetime!(2019-01-01 0:00),
158 /// );
159 /// ```
160 #[inline]
161 pub const fn new(date: Date, time: Time) -> Self {
162 Self { date, time }
163 }
164
165 /// Get the [`Date`] component of the `PrimitiveDateTime`.
166 ///
167 /// ```rust
168 /// # use time_macros::{date, datetime};
169 /// assert_eq!(datetime!(2019-01-01 0:00).date(), date!(2019-01-01));
170 /// ```
171 #[inline]
172 pub const fn date(self) -> Date {
173 self.date
174 }
175
176 /// Get the [`Time`] component of the `PrimitiveDateTime`.
177 ///
178 /// ```rust
179 /// # use time_macros::{datetime, time};
180 /// assert_eq!(datetime!(2019-01-01 0:00).time(), time!(0:00));
181 /// ```
182 #[inline]
183 pub const fn time(self) -> Time {
184 self.time
185 }
186
187 /// Get the year of the date.
188 ///
189 /// ```rust
190 /// # use time_macros::datetime;
191 /// assert_eq!(datetime!(2019-01-01 0:00).year(), 2019);
192 /// assert_eq!(datetime!(2019-12-31 0:00).year(), 2019);
193 /// assert_eq!(datetime!(2020-01-01 0:00).year(), 2020);
194 /// ```
195 #[inline]
196 pub const fn year(self) -> i32 {
197 self.date().year()
198 }
199
200 /// Get the month of the date.
201 ///
202 /// ```rust
203 /// # use time::Month;
204 /// # use time_macros::datetime;
205 /// assert_eq!(datetime!(2019-01-01 0:00).month(), Month::January);
206 /// assert_eq!(datetime!(2019-12-31 0:00).month(), Month::December);
207 /// ```
208 #[inline]
209 pub const fn month(self) -> Month {
210 self.date().month()
211 }
212
213 /// Get the day of the date.
214 ///
215 /// The returned value will always be in the range `1..=31`.
216 ///
217 /// ```rust
218 /// # use time_macros::datetime;
219 /// assert_eq!(datetime!(2019-01-01 0:00).day(), 1);
220 /// assert_eq!(datetime!(2019-12-31 0:00).day(), 31);
221 /// ```
222 #[inline]
223 pub const fn day(self) -> u8 {
224 self.date().day()
225 }
226
227 /// Get the day of the year.
228 ///
229 /// The returned value will always be in the range `1..=366` (`1..=365` for common years).
230 ///
231 /// ```rust
232 /// # use time_macros::datetime;
233 /// assert_eq!(datetime!(2019-01-01 0:00).ordinal(), 1);
234 /// assert_eq!(datetime!(2019-12-31 0:00).ordinal(), 365);
235 /// ```
236 #[inline]
237 pub const fn ordinal(self) -> u16 {
238 self.date().ordinal()
239 }
240
241 /// Get the ISO week number.
242 ///
243 /// The returned value will always be in the range `1..=53`.
244 ///
245 /// ```rust
246 /// # use time_macros::datetime;
247 /// assert_eq!(datetime!(2019-01-01 0:00).iso_week(), 1);
248 /// assert_eq!(datetime!(2019-10-04 0:00).iso_week(), 40);
249 /// assert_eq!(datetime!(2020-01-01 0:00).iso_week(), 1);
250 /// assert_eq!(datetime!(2020-12-31 0:00).iso_week(), 53);
251 /// assert_eq!(datetime!(2021-01-01 0:00).iso_week(), 53);
252 /// ```
253 #[inline]
254 pub const fn iso_week(self) -> u8 {
255 self.date().iso_week()
256 }
257
258 /// Get the week number where week 1 begins on the first Sunday.
259 ///
260 /// The returned value will always be in the range `0..=53`.
261 ///
262 /// ```rust
263 /// # use time_macros::datetime;
264 /// assert_eq!(datetime!(2019-01-01 0:00).sunday_based_week(), 0);
265 /// assert_eq!(datetime!(2020-01-01 0:00).sunday_based_week(), 0);
266 /// assert_eq!(datetime!(2020-12-31 0:00).sunday_based_week(), 52);
267 /// assert_eq!(datetime!(2021-01-01 0:00).sunday_based_week(), 0);
268 /// ```
269 #[inline]
270 pub const fn sunday_based_week(self) -> u8 {
271 self.date().sunday_based_week()
272 }
273
274 /// Get the week number where week 1 begins on the first Monday.
275 ///
276 /// The returned value will always be in the range `0..=53`.
277 ///
278 /// ```rust
279 /// # use time_macros::datetime;
280 /// assert_eq!(datetime!(2019-01-01 0:00).monday_based_week(), 0);
281 /// assert_eq!(datetime!(2020-01-01 0:00).monday_based_week(), 0);
282 /// assert_eq!(datetime!(2020-12-31 0:00).monday_based_week(), 52);
283 /// assert_eq!(datetime!(2021-01-01 0:00).monday_based_week(), 0);
284 /// ```
285 #[inline]
286 pub const fn monday_based_week(self) -> u8 {
287 self.date().monday_based_week()
288 }
289
290 /// Get the year, month, and day.
291 ///
292 /// ```rust
293 /// # use time::Month;
294 /// # use time_macros::datetime;
295 /// assert_eq!(
296 /// datetime!(2019-01-01 0:00).to_calendar_date(),
297 /// (2019, Month::January, 1)
298 /// );
299 /// ```
300 #[inline]
301 pub const fn to_calendar_date(self) -> (i32, Month, u8) {
302 self.date().to_calendar_date()
303 }
304
305 /// Get the year and ordinal day number.
306 ///
307 /// ```rust
308 /// # use time_macros::datetime;
309 /// assert_eq!(datetime!(2019-01-01 0:00).to_ordinal_date(), (2019, 1));
310 /// ```
311 #[inline]
312 pub const fn to_ordinal_date(self) -> (i32, u16) {
313 self.date().to_ordinal_date()
314 }
315
316 /// Get the ISO 8601 year, week number, and weekday.
317 ///
318 /// ```rust
319 /// # use time::Weekday::*;
320 /// # use time_macros::datetime;
321 /// assert_eq!(
322 /// datetime!(2019-01-01 0:00).to_iso_week_date(),
323 /// (2019, 1, Tuesday)
324 /// );
325 /// assert_eq!(
326 /// datetime!(2019-10-04 0:00).to_iso_week_date(),
327 /// (2019, 40, Friday)
328 /// );
329 /// assert_eq!(
330 /// datetime!(2020-01-01 0:00).to_iso_week_date(),
331 /// (2020, 1, Wednesday)
332 /// );
333 /// assert_eq!(
334 /// datetime!(2020-12-31 0:00).to_iso_week_date(),
335 /// (2020, 53, Thursday)
336 /// );
337 /// assert_eq!(
338 /// datetime!(2021-01-01 0:00).to_iso_week_date(),
339 /// (2020, 53, Friday)
340 /// );
341 /// ```
342 #[inline]
343 pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
344 self.date().to_iso_week_date()
345 }
346
347 /// Get the weekday.
348 ///
349 /// ```rust
350 /// # use time::Weekday::*;
351 /// # use time_macros::datetime;
352 /// assert_eq!(datetime!(2019-01-01 0:00).weekday(), Tuesday);
353 /// assert_eq!(datetime!(2019-02-01 0:00).weekday(), Friday);
354 /// assert_eq!(datetime!(2019-03-01 0:00).weekday(), Friday);
355 /// assert_eq!(datetime!(2019-04-01 0:00).weekday(), Monday);
356 /// assert_eq!(datetime!(2019-05-01 0:00).weekday(), Wednesday);
357 /// assert_eq!(datetime!(2019-06-01 0:00).weekday(), Saturday);
358 /// assert_eq!(datetime!(2019-07-01 0:00).weekday(), Monday);
359 /// assert_eq!(datetime!(2019-08-01 0:00).weekday(), Thursday);
360 /// assert_eq!(datetime!(2019-09-01 0:00).weekday(), Sunday);
361 /// assert_eq!(datetime!(2019-10-01 0:00).weekday(), Tuesday);
362 /// assert_eq!(datetime!(2019-11-01 0:00).weekday(), Friday);
363 /// assert_eq!(datetime!(2019-12-01 0:00).weekday(), Sunday);
364 /// ```
365 #[inline]
366 pub const fn weekday(self) -> Weekday {
367 self.date().weekday()
368 }
369
370 /// Get the Julian day for the date. The time is not taken into account for this calculation.
371 ///
372 /// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
373 /// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
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 /// Replace the clock hour.
831 ///
832 /// ```rust
833 /// # use time_macros::datetime;
834 /// assert_eq!(
835 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_hour(7),
836 /// Ok(datetime!(2022-02-18 07:02:03.004_005_006))
837 /// );
838 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
839 /// ```
840 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
841 #[inline]
842 pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
843 Ok(Self {
844 date: self.date,
845 time: const_try!(self.time.replace_hour(hour)),
846 })
847 }
848
849 /// Replace the minutes within the hour.
850 ///
851 /// ```rust
852 /// # use time_macros::datetime;
853 /// assert_eq!(
854 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_minute(7),
855 /// Ok(datetime!(2022-02-18 01:07:03.004_005_006))
856 /// );
857 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
858 /// ```
859 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
860 #[inline]
861 pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
862 Ok(Self {
863 date: self.date,
864 time: const_try!(self.time.replace_minute(minute)),
865 })
866 }
867
868 /// Replace the seconds within the minute.
869 ///
870 /// ```rust
871 /// # use time_macros::datetime;
872 /// assert_eq!(
873 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_second(7),
874 /// Ok(datetime!(2022-02-18 01:02:07.004_005_006))
875 /// );
876 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
877 /// ```
878 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
879 #[inline]
880 pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
881 Ok(Self {
882 date: self.date,
883 time: const_try!(self.time.replace_second(second)),
884 })
885 }
886
887 /// Replace the milliseconds within the second.
888 ///
889 /// ```rust
890 /// # use time_macros::datetime;
891 /// assert_eq!(
892 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_millisecond(7),
893 /// Ok(datetime!(2022-02-18 01:02:03.007))
894 /// );
895 /// assert!(datetime!(2022-02-18 01:02:03.004_005_006).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
896 /// ```
897 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
898 #[inline]
899 pub const fn replace_millisecond(
900 self,
901 millisecond: u16,
902 ) -> Result<Self, error::ComponentRange> {
903 Ok(Self {
904 date: self.date,
905 time: const_try!(self.time.replace_millisecond(millisecond)),
906 })
907 }
908
909 /// Replace the microseconds within the second.
910 ///
911 /// ```rust
912 /// # use time_macros::datetime;
913 /// assert_eq!(
914 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_microsecond(7_008),
915 /// Ok(datetime!(2022-02-18 01:02:03.007_008))
916 /// );
917 /// 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
918 /// ```
919 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
920 #[inline]
921 pub const fn replace_microsecond(
922 self,
923 microsecond: u32,
924 ) -> Result<Self, error::ComponentRange> {
925 Ok(Self {
926 date: self.date,
927 time: const_try!(self.time.replace_microsecond(microsecond)),
928 })
929 }
930
931 /// Replace the nanoseconds within the second.
932 ///
933 /// ```rust
934 /// # use time_macros::datetime;
935 /// assert_eq!(
936 /// datetime!(2022-02-18 01:02:03.004_005_006).replace_nanosecond(7_008_009),
937 /// Ok(datetime!(2022-02-18 01:02:03.007_008_009))
938 /// );
939 /// 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
940 /// ```
941 #[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
942 #[inline]
943 pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
944 Ok(Self {
945 date: self.date,
946 time: const_try!(self.time.replace_nanosecond(nanosecond)),
947 })
948 }
949}
950
951#[cfg(feature = "formatting")]
952impl PrimitiveDateTime {
953 /// Format the `PrimitiveDateTime` using the provided [format
954 /// description](crate::format_description).
955 #[inline]
956 pub fn format_into(
957 self,
958 output: &mut (impl io::Write + ?Sized),
959 format: &(impl Formattable + ?Sized),
960 ) -> Result<usize, error::Format> {
961 format.format_into(output, Some(self.date), Some(self.time), None)
962 }
963
964 /// Format the `PrimitiveDateTime` using the provided [format
965 /// description](crate::format_description).
966 ///
967 /// ```rust
968 /// # use time::format_description;
969 /// # use time_macros::datetime;
970 /// let format = format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")?;
971 /// assert_eq!(
972 /// datetime!(2020-01-02 03:04:05).format(&format)?,
973 /// "2020-01-02 03:04:05"
974 /// );
975 /// # Ok::<_, time::Error>(())
976 /// ```
977 #[inline]
978 pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
979 format.format(Some(self.date), Some(self.time), None)
980 }
981}
982
983#[cfg(feature = "parsing")]
984impl PrimitiveDateTime {
985 /// Parse a `PrimitiveDateTime` from the input using the provided [format
986 /// description](crate::format_description).
987 ///
988 /// ```rust
989 /// # use time::PrimitiveDateTime;
990 /// # use time_macros::{datetime, format_description};
991 /// let format = format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
992 /// assert_eq!(
993 /// PrimitiveDateTime::parse("2020-01-02 03:04:05", &format)?,
994 /// datetime!(2020-01-02 03:04:05)
995 /// );
996 /// # Ok::<_, time::Error>(())
997 /// ```
998 #[inline]
999 pub fn parse(
1000 input: &str,
1001 description: &(impl Parsable + ?Sized),
1002 ) -> Result<Self, error::Parse> {
1003 description.parse_primitive_date_time(input.as_bytes())
1004 }
1005}
1006
1007impl SmartDisplay for PrimitiveDateTime {
1008 type Metadata = ();
1009
1010 #[inline]
1011 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
1012 let width = smart_display::padded_width_of!(self.date, " ", self.time);
1013 Metadata::new(width, self, ())
1014 }
1015
1016 #[inline]
1017 fn fmt_with_metadata(
1018 &self,
1019 f: &mut fmt::Formatter<'_>,
1020 metadata: Metadata<Self>,
1021 ) -> fmt::Result {
1022 f.pad_with_width(
1023 metadata.unpadded_width(),
1024 format_args!("{} {}", self.date, self.time),
1025 )
1026 }
1027}
1028
1029impl fmt::Display for PrimitiveDateTime {
1030 #[inline]
1031 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1032 SmartDisplay::fmt(self, f)
1033 }
1034}
1035
1036impl fmt::Debug for PrimitiveDateTime {
1037 #[inline]
1038 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1039 fmt::Display::fmt(self, f)
1040 }
1041}
1042
1043impl Add<Duration> for PrimitiveDateTime {
1044 type Output = Self;
1045
1046 /// # Panics
1047 ///
1048 /// This may panic if an overflow occurs.
1049 #[inline]
1050 #[track_caller]
1051 fn add(self, duration: Duration) -> Self::Output {
1052 self.checked_add(duration)
1053 .expect("resulting value is out of range")
1054 }
1055}
1056
1057impl Add<StdDuration> for PrimitiveDateTime {
1058 type Output = Self;
1059
1060 /// # Panics
1061 ///
1062 /// This may panic if an overflow occurs.
1063 #[inline]
1064 #[track_caller]
1065 fn add(self, duration: StdDuration) -> Self::Output {
1066 let (is_next_day, time) = self.time.adjusting_add_std(duration);
1067
1068 Self {
1069 date: if is_next_day {
1070 (self.date + duration)
1071 .next_day()
1072 .expect("resulting value is out of range")
1073 } else {
1074 self.date + duration
1075 },
1076 time,
1077 }
1078 }
1079}
1080
1081impl AddAssign<Duration> for PrimitiveDateTime {
1082 /// # Panics
1083 ///
1084 /// This may panic if an overflow occurs.
1085 #[inline]
1086 #[track_caller]
1087 fn add_assign(&mut self, duration: Duration) {
1088 *self = *self + duration;
1089 }
1090}
1091
1092impl AddAssign<StdDuration> for PrimitiveDateTime {
1093 /// # Panics
1094 ///
1095 /// This may panic if an overflow occurs.
1096 #[inline]
1097 #[track_caller]
1098 fn add_assign(&mut self, duration: StdDuration) {
1099 *self = *self + duration;
1100 }
1101}
1102
1103impl Sub<Duration> for PrimitiveDateTime {
1104 type Output = Self;
1105
1106 /// # Panics
1107 ///
1108 /// This may panic if an overflow occurs.
1109 #[inline]
1110 #[track_caller]
1111 fn sub(self, duration: Duration) -> Self::Output {
1112 self.checked_sub(duration)
1113 .expect("resulting value is out of range")
1114 }
1115}
1116
1117impl Sub<StdDuration> for PrimitiveDateTime {
1118 type Output = Self;
1119
1120 /// # Panics
1121 ///
1122 /// This may panic if an overflow occurs.
1123 #[inline]
1124 #[track_caller]
1125 fn sub(self, duration: StdDuration) -> Self::Output {
1126 let (is_previous_day, time) = self.time.adjusting_sub_std(duration);
1127
1128 Self {
1129 date: if is_previous_day {
1130 (self.date - duration)
1131 .previous_day()
1132 .expect("resulting value is out of range")
1133 } else {
1134 self.date - duration
1135 },
1136 time,
1137 }
1138 }
1139}
1140
1141impl SubAssign<Duration> for PrimitiveDateTime {
1142 /// # Panics
1143 ///
1144 /// This may panic if an overflow occurs.
1145 #[inline]
1146 #[track_caller]
1147 fn sub_assign(&mut self, duration: Duration) {
1148 *self = *self - duration;
1149 }
1150}
1151
1152impl SubAssign<StdDuration> for PrimitiveDateTime {
1153 /// # Panics
1154 ///
1155 /// This may panic if an overflow occurs.
1156 #[inline]
1157 #[track_caller]
1158 fn sub_assign(&mut self, duration: StdDuration) {
1159 *self = *self - duration;
1160 }
1161}
1162
1163impl Sub for PrimitiveDateTime {
1164 type Output = Duration;
1165
1166 /// # Panics
1167 ///
1168 /// This may panic if an overflow occurs.
1169 #[inline]
1170 #[track_caller]
1171 fn sub(self, rhs: Self) -> Self::Output {
1172 (self.date - rhs.date) + (self.time - rhs.time)
1173 }
1174}