use std::sync::OnceLock;
use std::time::{SystemTime, UNIX_EPOCH};
static BOOT_TIME_SECS: OnceLock<i64> = OnceLock::new();
pub fn get_boot_time_secs() -> i64 {
*BOOT_TIME_SECS.get_or_init(|| {
if let Ok(boot_time) = i64::try_from(sysinfo::System::boot_time())
&& boot_time > 0
{
return boot_time;
}
let now_secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as i64;
let uptime_secs = i64::try_from(sysinfo::System::uptime())
.ok()
.filter(|uptime| *uptime > 0)
.unwrap_or(1);
now_secs.saturating_sub(uptime_secs)
})
}
pub fn boot_ns_to_epoch_ms(ns_since_boot: u64) -> u64 {
let boot_time_secs = get_boot_time_secs();
let boot_time_ms = boot_time_secs * 1000;
let offset_ms = (ns_since_boot / 1_000_000) as i64;
(boot_time_ms + offset_ms) as u64
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_boot_time_is_reasonable() {
let boot_time = get_boot_time_secs();
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as i64;
assert!(boot_time < now);
assert!(boot_time > 1577836800); }
#[test]
fn test_boot_ns_to_epoch_ms_conversion() {
let ns_since_boot = 1_000_000_000_000u64; let result_ms = boot_ns_to_epoch_ms(ns_since_boot);
let boot_time = get_boot_time_secs();
let expected_ms = (boot_time + 1000) * 1000;
assert_eq!(result_ms, expected_ms as u64);
}
}