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