use std::sync::LazyLock;
use time::format_description::well_known::Rfc3339;
use time::format_description::{self, FormatItem};
use time::{Date, OffsetDateTime, PrimitiveDateTime};
static DATE_FMT: LazyLock<Vec<FormatItem<'static>>> =
LazyLock::new(|| format_description::parse("[year]-[month]-[day]").expect("valid format"));
static LOCAL_FMTS: LazyLock<[Vec<FormatItem<'static>>; 6]> = LazyLock::new(|| {
[
format_description::parse("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond]")
.expect("valid format"),
format_description::parse("[year]-[month]-[day]T[hour]:[minute]:[second]")
.expect("valid format"),
format_description::parse("[year]-[month]-[day]T[hour]:[minute]").expect("valid format"),
format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]")
.expect("valid format"),
format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")
.expect("valid format"),
format_description::parse("[year]-[month]-[day] [hour]:[minute]").expect("valid format"),
]
});
pub(crate) fn is_valid_datetime(s: &str) -> bool {
if OffsetDateTime::parse(s, &Rfc3339).is_ok() {
return true;
}
for fmt in LOCAL_FMTS.iter() {
if PrimitiveDateTime::parse(s, fmt).is_ok() {
return true;
}
}
Date::parse(s, &*DATE_FMT).is_ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_datetimes() {
for s in [
"2026-06-01",
"2026-06-01T12:00:00",
"2026-06-01T12:00",
"2026-06-01T12:00:00.5",
"2026-06-01T12:00:00.123",
"2026-06-01 12:00:00",
"2026-06-01 12:00",
"2026-06-01 12:00:00.5",
"2026-06-01T12:00:00Z",
"2026-06-01T12:00:00+05:30",
"2026-06-01T12:00:00-05:00",
"2026-06-01T12:00:00+00:00",
"2026-06-01T12:00:00.5Z",
"2026-06-01T12:00:00.123+05:30",
] {
assert!(is_valid_datetime(s), "expected valid: {s}");
}
}
#[test]
fn invalid_datetimes() {
for s in [
"",
"2026",
"2026-06",
"not-a-date",
"13-04-2026",
"2026-06-01T",
"2026-06-01T12",
"2026-06-01T12:",
"2026-06-01T12:0", "2026-06-01T12:00:00 ", "2026-06-01T12:00:00+",
"2026-06-01T12:00:00X",
"2026-13-01", "2026-02-30", "2026-6-1", ] {
assert!(!is_valid_datetime(s), "expected invalid: {s}");
}
}
}