dtt/datetime/validate.rs
1// Copyright © 2025 DateTime (DTT) library.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! String-form validators for `DateTime` components.
5//!
6//! All entries are pure functions that mirror the bounds enforced by
7//! `DateTime::from_components` and `DateTime::parse`, so the validators
8//! and the constructors can never disagree.
9
10use super::{
11 DateTime, MAX_DAY, MAX_HOUR, MAX_ISO_WEEK, MAX_MICROSECOND,
12 MAX_MIN_SEC, MAX_MONTH, MAX_ORDINAL_DAY,
13};
14
15// -----------------------------------------------------------------------------
16// Validation Methods
17// -----------------------------------------------------------------------------
18
19impl DateTime {
20 /// Validates whether a string represents a valid day of the month.
21 #[must_use]
22 pub fn is_valid_day(day: &str) -> bool {
23 day.parse::<u8>().is_ok_and(|d| (1..=MAX_DAY).contains(&d))
24 }
25
26 /// Validates whether a string represents a valid hour.
27 #[must_use]
28 pub fn is_valid_hour(hour: &str) -> bool {
29 hour.parse::<u8>().is_ok_and(|h| h <= MAX_HOUR)
30 }
31
32 /// Validates whether a string represents a valid minute.
33 #[must_use]
34 pub fn is_valid_minute(minute: &str) -> bool {
35 minute.parse::<u8>().is_ok_and(|m| m <= MAX_MIN_SEC)
36 }
37
38 /// Validates whether a string represents a valid second.
39 #[must_use]
40 pub fn is_valid_second(second: &str) -> bool {
41 second.parse::<u8>().is_ok_and(|s| s <= MAX_MIN_SEC)
42 }
43
44 /// Validates whether a string represents a valid month.
45 #[must_use]
46 pub fn is_valid_month(month: &str) -> bool {
47 month
48 .parse::<u8>()
49 .is_ok_and(|m| (1..=MAX_MONTH).contains(&m))
50 }
51
52 /// Validates whether a string represents a valid year within the
53 /// supported `time::Date` range of `-9999..=9999`.
54 ///
55 /// This bound matches what `DateTime::from_components` can actually
56 /// construct, so the validator and the builder agree.
57 #[must_use]
58 pub fn is_valid_year(year: &str) -> bool {
59 year.parse::<i32>()
60 .is_ok_and(|y| (-9999..=9999).contains(&y))
61 }
62
63 /// Validates whether a string represents a valid microsecond.
64 #[must_use]
65 pub fn is_valid_microsecond(microsecond: &str) -> bool {
66 microsecond
67 .parse::<u32>()
68 .is_ok_and(|us| us <= MAX_MICROSECOND)
69 }
70
71 /// Validates whether a string represents a valid ordinal day of the year.
72 #[must_use]
73 pub fn is_valid_ordinal(ordinal: &str) -> bool {
74 ordinal
75 .parse::<u16>()
76 .is_ok_and(|o| (1..=MAX_ORDINAL_DAY).contains(&o))
77 }
78
79 /// Validates whether a string represents a valid ISO week number.
80 #[must_use]
81 pub fn is_valid_iso_week(week: &str) -> bool {
82 week.parse::<u8>()
83 .is_ok_and(|w| (1..=MAX_ISO_WEEK).contains(&w))
84 }
85
86 /// Validates whether a string represents a valid time in `HH:MM:SS` format.
87 #[must_use]
88 pub fn is_valid_time(time: &str) -> bool {
89 let parts: Vec<&str> = time.split(':').collect();
90 if parts.len() != 3 {
91 return false;
92 }
93
94 Self::is_valid_hour(parts[0])
95 && Self::is_valid_minute(parts[1])
96 && Self::is_valid_second(parts[2])
97 }
98}