Skip to main content

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}