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