chie_shared/utils/
time.rs1use chrono::Utc;
4
5#[inline]
7pub fn now_ms() -> i64 {
8 Utc::now().timestamp_millis()
9}
10
11#[inline]
13pub fn now_secs() -> i64 {
14 Utc::now().timestamp()
15}
16
17#[inline]
19pub fn ms_to_secs(ms: i64) -> i64 {
20 ms / 1000
21}
22
23#[inline]
25pub fn secs_to_ms(secs: i64) -> i64 {
26 secs * 1000
27}
28
29#[inline]
49pub fn is_timestamp_valid(timestamp_ms: i64, tolerance_ms: i64) -> bool {
50 let now = now_ms();
51 timestamp_ms <= now && (now - timestamp_ms) <= tolerance_ms
52}
53
54pub fn format_timestamp(timestamp_ms: i64) -> String {
57 use chrono::{DateTime, Utc};
58
59 if let Some(dt) = DateTime::<Utc>::from_timestamp(
60 timestamp_ms / 1000,
61 ((timestamp_ms % 1000) * 1_000_000) as u32,
62 ) {
63 dt.format("%Y-%m-%d %H:%M:%S UTC").to_string()
64 } else {
65 "Invalid timestamp".to_string()
66 }
67}
68
69pub fn parse_duration_str(s: &str) -> Option<u64> {
93 let s = s.trim().to_lowercase();
94 if s.is_empty() {
95 return None;
96 }
97
98 if s.ends_with("ms") {
100 return s.strip_suffix("ms")?.trim().parse().ok();
101 }
102
103 let mut total_ms = 0u64;
104 let mut current_num = String::new();
105
106 for ch in s.chars() {
107 if ch.is_ascii_digit() {
108 current_num.push(ch);
109 } else if !current_num.is_empty() {
110 let num: u64 = current_num.parse().ok()?;
111 current_num.clear();
112
113 let multiplier = match ch {
114 'd' => 24 * 60 * 60 * 1000, 'h' => 60 * 60 * 1000, 'm' => 60 * 1000, 's' => 1000, _ => return None,
119 };
120
121 total_ms = total_ms.checked_add(num.checked_mul(multiplier)?)?;
122 }
123 }
124
125 if total_ms == 0 { None } else { Some(total_ms) }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn test_timestamp_conversion() {
134 let secs = 1000;
135 let ms = secs_to_ms(secs);
136 assert_eq!(ms, 1_000_000);
137 assert_eq!(ms_to_secs(ms), secs);
138 }
139
140 #[test]
141 fn test_timestamp_validation() {
142 let now = now_ms();
143 assert!(is_timestamp_valid(now, 1000));
144 assert!(is_timestamp_valid(now - 500, 1000));
145 assert!(!is_timestamp_valid(now + 1000, 1000));
146 assert!(!is_timestamp_valid(now - 2000, 1000));
147 }
148
149 #[test]
150 fn test_format_timestamp() {
151 let ts = 1_702_742_445_000_i64; let formatted = format_timestamp(ts);
154 assert!(formatted.contains("2023-12-16"));
155 assert!(formatted.contains("UTC"));
156
157 let invalid = format_timestamp(i64::MAX);
159 assert_eq!(invalid, "Invalid timestamp");
160 }
161
162 #[test]
163 fn test_parse_duration_str() {
164 assert_eq!(parse_duration_str("500ms"), Some(500));
165 assert_eq!(parse_duration_str("5s"), Some(5000));
166 assert_eq!(parse_duration_str("2m"), Some(120_000));
167 assert_eq!(parse_duration_str("1h"), Some(3_600_000));
168 assert_eq!(parse_duration_str("1d"), Some(86_400_000));
169 assert_eq!(parse_duration_str("1h30m"), Some(5_400_000));
170 assert_eq!(parse_duration_str("2h15m30s"), Some(8_130_000));
171 assert_eq!(parse_duration_str(""), None);
172 assert_eq!(parse_duration_str("invalid"), None);
173 assert_eq!(parse_duration_str("10"), None); }
175}