use crate::{ChronoError, PosixNs, Unit};
pub fn filetime_hilo(low: u32, high: u32) -> Result<PosixNs, ChronoError> {
let ft = (u64::from(high) << 32) | u64::from(low);
let ticks = i64::try_from(ft).map_err(|_| ChronoError::OutOfRange {
what: "filetime",
value: i128::from(ft),
})?;
crate::format("filetime")?.decode_int(ticks)
}
#[cfg(feature = "leap")]
#[must_use]
pub fn gps_week_tow(week: u32, tow: f64) -> crate::leap::LeapReading {
crate::leap::from_gps_seconds(f64::from(week) * 604_800.0 + tow)
}
#[must_use]
pub fn vmsd(high: i32, low: i32) -> PosixNs {
let us = (i128::from(high) << 32) | i128::from(low.cast_unsigned());
PosixNs(us * 1_000)
}
#[must_use]
pub fn relative(anchor: PosixNs, ticks: i64, unit: Unit) -> PosixNs {
PosixNs(anchor.0 + i128::from(ticks) * unit.nanos())
}
#[must_use]
pub fn unix_sec_nsec(sec: i64, nsec: u32) -> PosixNs {
PosixNs(i128::from(sec) * 1_000_000_000 + i128::from(nsec))
}
fn civil_utc(
year: i16,
month: i8,
day: i8,
hour: i8,
minute: i8,
second: i8,
) -> Result<PosixNs, ChronoError> {
let dt = jiff::civil::DateTime::new(year, month, day, hour, minute, second, 0)
.map_err(|e| ChronoError::Render(e.to_string()))?;
let ts = dt
.to_zoned(jiff::tz::TimeZone::UTC)
.map_err(|e| ChronoError::Render(e.to_string()))?
.timestamp();
Ok(PosixNs(ts.as_nanosecond()))
}
pub fn oracle_date(b: [u8; 7]) -> Result<PosixNs, ChronoError> {
let year = (i16::from(b[0]) - 100) * 100 + (i16::from(b[1]) - 100);
let f = |v: u8, off: i16| (i16::from(v) - off) as i8;
civil_utc(
year,
f(b[2], 0),
f(b[3], 0),
f(b[4], 1),
f(b[5], 1),
f(b[6], 1),
)
}
pub fn iso9660(b: [u8; 7]) -> Result<PosixNs, ChronoError> {
let year = 1900 + i16::from(b[0]);
let civil = civil_utc(
year, b[1] as i8, b[2] as i8, b[3] as i8, b[4] as i8, b[5] as i8,
)?;
let offset_ns = i128::from(b[6] as i8) * 15 * 60 * 1_000_000_000;
Ok(PosixNs(civil.0 - offset_ns))
}
#[must_use]
pub fn ext4_extra(secs: i64, extra: u32) -> PosixNs {
let epoch_bits = i128::from(extra & 0x3);
let nanos = i128::from(extra >> 2);
PosixNs((i128::from(secs) + (epoch_bits << 32)) * 1_000_000_000 + nanos)
}
pub fn cp56time2a(b: [u8; 7]) -> Result<PosixNs, ChronoError> {
let ms = u16::from(b[0]) | (u16::from(b[1]) << 8);
let sub_ns = i128::from(ms % 1000) * 1_000_000;
let inst = civil_utc(
2000 + i16::from(b[6] & 0x7F),
(b[5] & 0x0F) as i8,
(b[4] & 0x1F) as i8,
(b[3] & 0x1F) as i8,
(b[2] & 0x3F) as i8,
(ms / 1000) as i8,
)?;
Ok(PosixNs(inst.0 + sub_ns))
}
pub fn udf(b: [u8; 12]) -> Result<PosixNs, ChronoError> {
let year = (u16::from(b[2]) | (u16::from(b[3]) << 8)) as i16;
let civil = civil_utc(
year, b[4] as i8, b[5] as i8, b[6] as i8, b[7] as i8, b[8] as i8,
)?;
let sub_ns =
i128::from(b[9]) * 10_000_000 + i128::from(b[10]) * 100_000 + i128::from(b[11]) * 1_000;
let tz12 = (u16::from(b[0]) | (u16::from(b[1]) << 8)) & 0x0FFF;
let tz_min = if tz12 == 0 || tz12 == 0x800 {
0
} else if tz12 & 0x800 != 0 {
i32::from(tz12) - 0x1000
} else {
i32::from(tz12)
};
Ok(PosixNs(
civil.0 + sub_ns - i128::from(tz_min) * 60 * 1_000_000_000,
))
}