#![cfg(all(feature = "jiff", any(feature = "oxrdf", feature = "rudof")))]
use xsd::{PrimitiveValue, TimezoneOffset, Value};
fn compare(input: &str) {
let ours = xsd::parse_datetime(input);
let reference = input.parse::<oxsdatatypes::DateTime>();
assert_eq!(ours.is_ok(), reference.is_ok(), "{input}");
if let (Ok(ours), Ok(reference)) = (ours, reference) {
let Value::Primitive(PrimitiveValue::DateTime(datetime)) = ours.clone() else {
panic!("wrong datatype");
};
assert_eq!(
datetime.timezone().map(|o| o.to_string()),
reference.timezone_offset().map(|o| o.to_string()),
"{input}"
);
if datetime.subsec_nanosecond() == 0 {
assert_eq!(
xsd::parse_datetime(reference.to_string()).unwrap(),
ours,
"{input}"
);
}
assert!(
ours.to_string()
.parse::<oxsdatatypes::DateTime>()
.unwrap()
.is_identical_with(reference),
"{input}"
);
}
}
#[test]
fn datetime_calendar_and_clock_grid_matches_independent_parser() {
for year in [
"-9999", "-0400", "-0100", "-0001", "0000", "0001", "1900", "2000", "9999",
] {
for month in [0, 1, 2, 4, 13] {
for day in [0, 1, 28, 29, 30, 31, 32] {
for clock in [
"00:00:00",
"23:59:59.999999999",
"23:59:60",
"24:00:00.000",
"24:00:01",
] {
for suffix in ["", "Z", "+05:45", "-14:00"] {
compare(&format!("{year}-{month:02}-{day:02}T{clock}{suffix}"));
}
}
}
}
}
}
#[test]
fn datetime_all_offsets_match_independent_parser() {
for minutes in -840..=840 {
let offset = TimezoneOffset::from_minutes(minutes).unwrap();
for value in ["-0001-12-31T24:00:00", "2024-02-29T12:34:56.000000001"] {
compare(&format!("{value}{offset}"));
}
}
for suffix in [
"+00:00", "-00:00", "+14:01", "-14:01", "+05:60", "+0500", "z", "Zjunk",
] {
compare(&format!("2024-02-29T12:34:56{suffix}"));
}
}
#[test]
fn datetime_representation_limits_are_explicit() {
for input in [
"9999-12-31T24:00:00Z",
"10000-01-01T00:00:00Z",
"2026-01-02T12:34:56.0000000001Z",
] {
assert!(input.parse::<oxsdatatypes::DateTime>().is_ok());
assert!(xsd::parse_datetime(input).is_err());
}
}
#[test]
fn fractional_seconds_do_not_advance_calendar_fields() {
for date in ["-9999-01-01", "-0001-12-31", "0000-02-29", "9999-12-31"] {
for suffix in ["", "Z", "+14:00", "-14:00"] {
let input = format!("{date}T23:59:59.999999999{suffix}");
assert_eq!(xsd::parse_datetime(&input).unwrap().to_string(), input);
compare(&input);
}
}
}