1use chrono::{DateTime, Local, TimeZone, Utc};
4
5pub fn now_millis() -> i64 {
7 Utc::now().timestamp_millis()
8}
9
10pub fn now_seconds() -> i64 {
12 Utc::now().timestamp()
13}
14
15pub fn now_micros() -> i64 {
17 Utc::now().timestamp_micros()
18}
19
20pub fn format_now_utc(fmt: &str) -> String {
29 Utc::now().format(fmt).to_string()
30}
31
32pub fn format_now_local(fmt: &str) -> String {
34 Local::now().format(fmt).to_string()
35}
36
37pub fn format_timestamp_utc(ts_seconds: i64, fmt: &str) -> Option<String> {
41 Utc.timestamp_opt(ts_seconds, 0)
42 .single()
43 .map(|dt: DateTime<Utc>| dt.format(fmt).to_string())
44}
45
46pub fn format_timestamp_local(ts_seconds: i64, fmt: &str) -> Option<String> {
48 Local
49 .timestamp_opt(ts_seconds, 0)
50 .single()
51 .map(|dt| dt.format(fmt).to_string())
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn now_millis_is_close_to_chrono() {
60 let mine = now_millis();
61 let chrono_now = Utc::now().timestamp_millis();
62 assert!((chrono_now - mine).abs() < 1000);
63 }
64
65 #[test]
66 fn now_seconds_is_close_to_chrono() {
67 let mine = now_seconds();
68 let chrono_now = Utc::now().timestamp();
69 assert!((chrono_now - mine).abs() <= 1);
70 }
71
72 #[test]
73 fn format_timestamp_utc_known_value() {
74 let s = format_timestamp_utc(1_704_067_200, "%Y-%m-%d %H:%M:%S").unwrap();
76 assert_eq!(s, "2024-01-01 00:00:00");
77 }
78
79 #[test]
80 fn format_timestamp_utc_rejects_out_of_range() {
81 assert!(format_timestamp_utc(i64::MAX, "%Y").is_none());
82 }
83
84 #[test]
85 fn format_now_utc_produces_expected_length() {
86 let s = format_now_utc("%Y-%m-%dT%H:%M:%SZ");
87 assert_eq!(s.len(), 20);
88 assert!(s.ends_with('Z'));
89 }
90}