pingap_util/
datetime.rs

1// Copyright 2024-2025 Tree xie.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use once_cell::sync::Lazy;
16use std::time::{Duration, SystemTime, UNIX_EPOCH};
17
18// 2022-05-07: 1651852800
19// const SUPER_TIMESTAMP: u64 = 1651852800;
20static SUPER_TIMESTAMP: Lazy<SystemTime> = Lazy::new(|| {
21    UNIX_EPOCH
22        .checked_add(Duration::from_secs(1651852800))
23        .unwrap_or(SystemTime::now())
24});
25
26/// Returns the number of seconds elapsed since SUPER_TIMESTAMP
27/// Returns 0 if the current time is before SUPER_TIMESTAMP
28pub fn get_super_ts() -> u32 {
29    if let Ok(value) = SystemTime::now().duration_since(*SUPER_TIMESTAMP) {
30        value.as_secs() as u32
31    } else {
32        0
33    }
34}
35
36/// Returns the duration since UNIX epoch (1970-01-01 00:00:00 UTC)
37#[inline]
38pub fn now() -> Duration {
39    SystemTime::now()
40        .duration_since(UNIX_EPOCH)
41        .unwrap_or_default()
42}
43
44/// Returns the current timestamp in milliseconds since UNIX epoch
45#[inline]
46pub fn now_ms() -> u64 {
47    now().as_millis() as u64
48}
49
50/// Returns the current timestamp in seconds since UNIX epoch
51#[inline]
52pub fn now_sec() -> u64 {
53    now().as_secs()
54}
55
56/// Calculates latency between a previous timestamp and now
57/// If previous timestamp is None, returns current timestamp
58/// Returns: Some(latency in milliseconds) or Some(current timestamp) if input is None
59#[inline]
60pub fn get_latency(value: &Option<u64>) -> Option<u64> {
61    let current = now_ms();
62    if let Some(value) = value {
63        Some(current - value)
64    } else {
65        Some(current)
66    }
67}
68
69/// Returns the elapsed time in milliseconds since the given SystemTime
70#[inline]
71pub fn elapsed_ms(time: SystemTime) -> u64 {
72    time.elapsed().unwrap_or_default().as_millis() as u64
73}
74
75/// Returns the elapsed time in seconds (as f64) since the given SystemTime
76#[inline]
77pub fn elapsed_second(time: SystemTime) -> f64 {
78    time.elapsed().unwrap_or_default().as_millis() as f64 / 1000.0
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84    use pretty_assertions::assert_eq;
85
86    #[test]
87    fn test_get_super_ts() {
88        assert_eq!(get_super_ts().to_string().len() >= 8, true);
89    }
90
91    #[test]
92    fn test_now() {
93        assert_eq!(10, now_sec().to_string().len());
94        assert_eq!(13, now_ms().to_string().len());
95    }
96
97    #[test]
98    fn test_elapsed_ms() {
99        let start = SystemTime::now()
100            .checked_sub(Duration::from_secs(55))
101            .unwrap();
102        assert_eq!(5, elapsed_ms(start).to_string().len());
103        assert_eq!(elapsed_second(start).to_string().starts_with("55"), true);
104    }
105
106    #[test]
107    fn test_get_latency() {
108        let d = get_latency(&None);
109        assert_eq!(true, d.is_some());
110        assert_eq!(true, get_latency(&d).is_some());
111    }
112}