#![allow(clippy::all, clippy::pedantic, clippy::restriction, warnings)]
#[cfg(feature = "time")]
mod tests {
use deep_time::{Dt, Scale};
use time::{Duration, OffsetDateTime, Timestamp, UtcDateTime, UtcOffset};
fn assert_ns_eq(a: Dt, b: Dt, label: &str) {
assert_eq!(
a.to_ns().0,
b.to_ns().0,
"{label}: ns mismatch (attos {} vs {})",
a.attos,
b.attos
);
}
#[test]
fn timestamp_roundtrip_unix_epoch() {
let dt = Dt::from_ymd(1970, 1, 1, Scale::UTC, 0, 0, 0, 0);
let ts = dt.to_time_timestamp();
assert_eq!(ts.as_seconds(), 0);
assert_eq!(ts.as_nanoseconds(), 0);
assert_ns_eq(Dt::from_time_timestamp(ts), dt, "unix epoch");
}
#[test]
fn timestamp_roundtrip_j2000_utc_noon() {
let dt = Dt::from_ymd(2000, 1, 1, Scale::UTC, 12, 0, 0, 0);
let ts = dt.to_time_timestamp();
assert_eq!(ts.as_seconds(), 946_728_000);
assert_ns_eq(Dt::from_time_timestamp(ts), dt, "j2000 utc noon");
}
#[test]
fn timestamp_roundtrip_modern_with_subsec() {
let dt = Dt::from_ymd(2024, 4, 15, Scale::UTC, 14, 30, 45, 123_456_789_000_000_000);
let ts = dt.to_time_timestamp();
assert_eq!(ts.as_seconds(), 1_713_191_445);
assert_eq!(ts.as_nanoseconds(), 1_713_191_445_123_456_789);
assert_ns_eq(Dt::from_time_timestamp(ts), dt, "2024 with ns");
}
#[test]
fn timestamp_roundtrip_near_leap_seconds() {
let dt = Dt::from_ymd(2017, 1, 1, Scale::UTC, 0, 0, 0, 0);
let ts = dt.to_time_timestamp();
assert_eq!(ts.as_seconds(), 1_483_228_800);
assert_ns_eq(Dt::from_time_timestamp(ts), dt, "2017-01-01 UTC");
}
#[test]
fn timestamp_from_tai_uses_utc_unix() {
let utc = Dt::from_ymd(2020, 1, 1, Scale::UTC, 0, 0, 0, 0);
let tai = utc.to_tai();
assert_eq!(
utc.to_time_timestamp().as_nanoseconds(),
tai.to_time_timestamp().as_nanoseconds()
);
}
#[test]
fn timestamp_is_posix_not_tai() {
let utc = Dt::from_ymd(2020, 1, 1, Scale::UTC, 0, 0, 0, 0);
let ts = utc.to_time_timestamp();
assert_eq!(ts.as_seconds(), 1_577_836_800);
let back = Dt::from_time_timestamp(ts);
let ymd = back.target(Scale::UTC).to_ymd();
assert_eq!(ymd.yr(), 2020);
assert_eq!(ymd.mo(), 1);
assert_eq!(ymd.day(), 1);
assert_eq!(ymd.hr(), 0);
assert_eq!(ymd.min(), 0);
assert_eq!(ymd.sec(), 0);
}
#[test]
fn offset_datetime_utc_roundtrip() {
let dt = Dt::from_ymd(2019, 6, 15, Scale::UTC, 12, 0, 0, 0);
let odt = dt.to_time_offset_datetime_utc();
assert_eq!(odt.offset(), UtcOffset::UTC);
assert_eq!(odt.unix_timestamp(), 1_560_600_000);
assert_ns_eq(Dt::from_time_offset_datetime(odt), dt, "offset utc");
}
#[test]
fn offset_datetime_non_utc_offset_uses_instant() {
let odt = OffsetDateTime::from_unix_timestamp(1_713_191_400)
.unwrap()
.to_offset(UtcOffset::from_hms(-4, 0, 0).unwrap());
assert_eq!(odt.hour(), 10);
assert_eq!(odt.minute(), 30);
let dt = Dt::from_time_offset_datetime(odt);
let ymd = dt.target(Scale::UTC).to_ymd();
assert_eq!(ymd.yr(), 2024);
assert_eq!(ymd.mo(), 4);
assert_eq!(ymd.day(), 15);
assert_eq!(ymd.hr(), 14);
assert_eq!(ymd.min(), 30);
assert_eq!(ymd.sec(), 0);
}
#[test]
fn utc_datetime_roundtrip() {
let dt = Dt::from_ymd(1999, 12, 31, Scale::UTC, 23, 59, 59, 0);
let udt = dt.to_time_utc_datetime();
assert_eq!(udt.unix_timestamp(), 946_684_799);
assert_ns_eq(Dt::from_time_utc_datetime(udt), dt, "utc datetime");
}
#[test]
fn utc_datetime_from_timestamp_path() {
let ts = Timestamp::from_seconds(1_000_000_000).unwrap();
let udt: UtcDateTime = ts.to_utc();
let dt = Dt::from_time_utc_datetime(udt);
assert_eq!(dt.to_time_timestamp().as_seconds(), 1_000_000_000);
}
#[test]
fn duration_roundtrip() {
let span = Dt::from_ns_floor(3_600_000_000_000 + 123, 0, Scale::TAI); let dur = span.to_time_duration();
assert_eq!(dur.whole_seconds(), 3_600);
assert_eq!(dur.subsec_nanoseconds(), 123);
assert_ns_eq(Dt::from_time_duration(dur), span, "duration");
}
#[test]
fn duration_negative_roundtrip() {
let span = Dt::from_ns_floor(-5_000_000_001, 0, Scale::TAI);
let dur = span.to_time_duration();
assert!(dur.is_negative());
assert_eq!(dur.whole_nanoseconds(), -5_000_000_001);
assert_ns_eq(Dt::from_time_duration(dur), span, "neg duration");
}
#[test]
fn duration_truncates_sub_nanosecond() {
let span = Dt::from_attos(1_500_000_000, Scale::TAI);
let dur = span.to_time_duration();
assert_eq!(dur.whole_nanoseconds(), 1);
}
#[test]
fn duration_saturates_at_extremes() {
let huge = Dt::from_attos(i128::MAX / 2, Scale::TAI);
assert_eq!(huge.to_time_duration(), Duration::MAX);
let tiny = Dt::from_attos(i128::MIN / 2, Scale::TAI);
assert_eq!(tiny.to_time_duration(), Duration::MIN);
}
#[test]
fn timestamp_saturates_out_of_range() {
let far_future = Dt::from_ymd(50_000, 1, 1, Scale::UTC, 0, 0, 0, 0);
assert_eq!(far_future.to_time_timestamp(), Timestamp::MAX);
let far_past = Dt::from_ymd(-50_000, 1, 1, Scale::UTC, 0, 0, 0, 0);
assert_eq!(far_past.to_time_timestamp(), Timestamp::MIN);
}
}