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