Files
core/test/rust/runtime/calendar.rs
T
2026-11-03 03:32:07 +00:00

125 lines
4.1 KiB
Rust

use dever_runtime::time::{
self,
calendar::{Date, DateTime, Duration, Time},
};
#[test]
fn rfc3339_offsets_normalize_to_utc_at_millisecond_precision() {
assert_eq!(
DateTime::parse("2024-02-29T12:34:56.12+08:00")
.unwrap()
.format()
.unwrap(),
"2024-02-29T04:34:56.120Z"
);
for value in [
"1969-12-31T23:59:59.999Z",
"0000-01-01T00:00:00Z",
"9999-12-31T23:59:59.999Z",
] {
assert_eq!(DateTime::parse(value).unwrap().format().unwrap(), value);
}
for value in [
"2023-02-29T00:00:00Z",
"2024-02-29T00:00:00.1230Z",
"2024-02-29T00:00:00.1234Z",
"2024-12-31T23:59:60Z",
"2024-01-01T00:00:00",
"9999-12-31T23:30:00-01:00",
"0000-01-01T00:00:00+01:00",
] {
assert!(DateTime::parse(value).is_err(), "{value}");
}
}
#[test]
fn date_and_time_spellings_are_strict_and_zero_fractions_normalize() {
assert_eq!(
Date::parse("2024-02-29").unwrap().format().unwrap(),
"2024-02-29"
);
for value in ["2024-2-29", "2023-02-29", "10000-01-01", "2024-01-01 "] {
assert!(Date::parse(value).is_err(), "{value}");
}
assert_eq!(
Time::parse("12:34:56.000").unwrap().format().unwrap(),
"12:34:56"
);
assert_eq!(
Time::parse("12:34:56.001").unwrap().format().unwrap(),
"12:34:56.001"
);
for value in [
"24:00:00",
"23:60:00",
"23:59:60",
"12:34:56.1",
"12:34:56.12",
"12:34:56.1234",
" 12:34:56",
] {
assert!(Time::parse(value).is_err(), "{value}");
}
}
#[test]
fn arithmetic_keeps_i64_values_and_checks_overflow_separately_from_formatting() {
let epoch = DateTime::parse("1970-01-01T00:00:00Z").unwrap();
assert_eq!(
epoch
.checked_sub(Duration::from_millis(1))
.unwrap()
.format()
.unwrap(),
"1969-12-31T23:59:59.999Z"
);
let maximum = epoch.checked_add(Duration::from_millis(i64::MAX)).unwrap();
let minimum = epoch.checked_add(Duration::from_millis(i64::MIN)).unwrap();
assert!(maximum.format().is_err());
assert!(maximum.checked_add(Duration::from_millis(1)).is_err());
assert!(minimum.checked_sub(Duration::from_millis(1)).is_err());
assert!(maximum.difference(minimum).is_err());
assert_eq!(epoch.difference(epoch).unwrap().millis(), 0);
}
#[test]
fn temporal_values_are_inline_and_clocks_round_trip() {
assert_eq!(std::mem::size_of::<DateTime>(), 8);
assert_eq!(std::mem::size_of::<Date>(), 8);
assert_eq!(std::mem::size_of::<Time>(), 8);
assert_eq!(std::mem::size_of::<Duration>(), 8);
assert!(!std::mem::needs_drop::<DateTime>());
let now = DateTime::now().unwrap();
assert_eq!(DateTime::parse(&now.format().unwrap()).unwrap(), now);
assert!(time::unix_millis().is_ok());
let first = time::monotonic_nanos().unwrap();
assert!(time::monotonic_nanos().unwrap() >= first);
}
#[cfg(feature = "wire")]
#[test]
fn wire_uses_canonical_strings_and_integer_durations() {
let value: DateTime = serde_json::from_str(r#""2024-02-29T12:34:56.12+08:00""#).unwrap();
assert_eq!(
serde_json::to_string(&value).unwrap(),
r#""2024-02-29T04:34:56.120Z""#
);
let escaped: Date = serde_json::from_str(r#""\u0032024-02-29""#).unwrap();
assert_eq!(serde_json::to_string(&escaped).unwrap(), r#""2024-02-29""#);
let clock: Time = serde_json::from_str(r#""12:34:56.000""#).unwrap();
assert_eq!(serde_json::to_string(&clock).unwrap(), r#""12:34:56""#);
assert!(serde_json::from_str::<DateTime>("0").is_err());
assert!(serde_json::from_str::<Duration>("1.0").is_err());
assert!(serde_json::from_str::<Duration>(r#""1""#).is_err());
let duration: Duration = serde_json::from_str("9223372036854775807").unwrap();
assert_eq!(
serde_json::to_string(&duration).unwrap(),
"9223372036854775807"
);
let far = DateTime::parse("1970-01-01T00:00:00Z")
.unwrap()
.checked_add(duration)
.unwrap();
assert!(serde_json::to_string(&far).is_err());
}