use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime};
use rust_decimal::Decimal;
pub fn to_decimal(s: &str) -> Option<Decimal> {
s.trim().parse().ok()
}
pub fn to_date(s: &str) -> Option<NaiveDate> {
let s = s.trim();
let date_part = &s[..s.len().min(10)];
NaiveDate::parse_from_str(date_part, "%Y-%m-%d").ok()
}
pub fn to_datetime(s: &str) -> Option<DateTime<FixedOffset>> {
let s = s.trim();
if let Ok(dt) = DateTime::parse_from_rfc3339(s) {
return Some(dt);
}
for fmt in ["%Y-%m-%dT%H:%M:%S%.f", "%Y-%m-%dT%H:%M:%S"] {
if let Ok(naive) = NaiveDateTime::parse_from_str(s, fmt) {
return Some(DateTime::from_naive_utc_and_offset(
naive,
FixedOffset::east_opt(0).unwrap(),
));
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn conversions() {
assert_eq!(to_decimal(" 7866240.23491 ").unwrap().to_string(), "7866240.23491");
assert!(to_decimal("not-a-number").is_none());
assert_eq!(to_date("2026-06-27").unwrap().to_string(), "2026-06-27");
assert_eq!(to_date("2026-06-27+02:00").unwrap().to_string(), "2026-06-27");
assert!(to_datetime("2026-06-27T10:30:00Z").is_some());
assert!(to_datetime("2026-06-27T10:30:00").is_some());
assert!(to_datetime("2026-06-27T10:30:00.123+01:00").is_some());
}
}