ntp-timer 0.1.0

A lightweight NTP time synchronization library for Rust applications. Provides in-process cached global time with background sync and clock-jump detection.
Documentation
use std::time::Instant;
use tracing::{debug, warn};

/// Core data structure for global timer management
#[derive(Debug, Clone)]
pub struct GlobalTimer {
    /// Initial timestamp fetched from NTP
    pub base_timestamp: i64,
    /// Reference point of system clock
    pub base_instant: Instant,
    /// Timestamp of last NTP synchronization
    pub last_sync_at: Instant,
}

impl GlobalTimer {
    /// Creates a new global timer with the given NTP timestamp
    pub fn new(initial_timestamp: i64) -> Self {
        let base_instant = Instant::now();
        debug!("初始化全局计时器,时间戳: {}", initial_timestamp);

        Self {
            base_timestamp: initial_timestamp,
            base_instant,
            last_sync_at: base_instant,
        }
    }

    /// Gets the current timestamp via fast local calculation
    pub fn get_current_timestamp(&self) -> i64 {
        let elapsed_secs = self.base_instant.elapsed().as_secs() as i64;
        self.base_timestamp + elapsed_secs
    }

    /// Detects if a clock jump occurred by comparing NTP timestamp with internal estimate
    pub fn detect_clock_jump(&self, new_ntp_timestamp: i64, threshold: i64) -> bool {
        let current_estimate = self.get_current_timestamp();
        let drift = (new_ntp_timestamp - current_estimate).abs();

        if drift > threshold {
            warn!(
                drift_secs = drift,
                threshold_secs = threshold,
                "检测到系统时钟跳跃"
            );
            true
        } else {
            debug!(drift_secs = drift, "系统时钟漂移在正常范围内");
            false
        }
    }

    /// 更新时间戳(处理时钟跳跃或漂移纠正)
    pub fn update_timestamp(&mut self, new_timestamp: i64, is_jump: bool) {
        self.base_timestamp = new_timestamp;
        self.base_instant = Instant::now();
        self.last_sync_at = self.base_instant;

        if is_jump {
            warn!("检测到系统时钟跳跃,重新初始化计时器");
        } else {
            debug!("基准时间戳已更新(漂移纠正)");
        }
    }

    /// 检查是否需要进行同步
    pub fn should_sync(&self, sync_interval: u64) -> bool {
        self.last_sync_at.elapsed().as_secs() >= sync_interval
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;

    #[test]
    fn test_timer_creation() {
        let timer = GlobalTimer::new(1000);
        assert_eq!(timer.base_timestamp, 1000);
    }

    #[test]
    fn test_get_current_timestamp() {
        let timer = GlobalTimer::new(1000);
        thread::sleep(std::time::Duration::from_millis(100));
        let ts = timer.get_current_timestamp();
        assert!(ts >= 1000);
    }

    #[test]
    fn test_detect_clock_jump() {
        let timer = GlobalTimer::new(1000);
        assert!(!timer.detect_clock_jump(1001, 5));
        assert!(timer.detect_clock_jump(1010, 5));
    }

    #[test]
    fn test_update_timestamp() {
        let mut timer = GlobalTimer::new(1000);
        timer.update_timestamp(2000, true);
        assert_eq!(timer.base_timestamp, 2000);
    }

    #[test]
    fn test_should_sync() {
        let timer = GlobalTimer::new(1000);
        assert!(!timer.should_sync(10));
        thread::sleep(std::time::Duration::from_secs(1));
        assert!(timer.should_sync(0));
    }
}