use crate::schema::canonical::error::ParseError;
use chrono::{DateTime, Datelike, SecondsFormat, Utc};
use serde_json::Value;
fn check_year_range(payload: &DateTime<Utc>) -> Result<(), ParseError> {
let year = payload.year();
if !(0..=9999).contains(&year) {
return Err(ParseError::OutOfRange("datetime year"));
}
Ok(())
}
pub fn to_text(payload: &DateTime<Utc>) -> Result<String, ParseError> {
check_year_range(payload)?;
Ok(payload.to_rfc3339_opts(SecondsFormat::Nanos, true))
}
pub fn from_text(s: &str) -> Result<DateTime<Utc>, ParseError> {
if s.is_empty() {
return Err(ParseError::Empty);
}
let parsed = DateTime::parse_from_rfc3339(s)
.map_err(|e| ParseError::BadFormat(format!("RFC 3339 expected: {e}")))?;
Ok(parsed.with_timezone(&Utc))
}
pub fn to_json(payload: &DateTime<Utc>) -> Result<Value, ParseError> {
Ok(Value::String(to_text(payload)?))
}
pub fn from_json(value: &Value) -> Result<DateTime<Utc>, ParseError> {
match value {
Value::String(s) => from_text(s),
_ => Err(ParseError::TypeField {
expected: "string",
field: None,
}),
}
}
#[cfg(test)]
mod tests;