use chrono::{DateTime, Local, TimeZone, Utc};
pub fn now_millis() -> i64 {
Utc::now().timestamp_millis()
}
pub fn now_seconds() -> i64 {
Utc::now().timestamp()
}
pub fn now_micros() -> i64 {
Utc::now().timestamp_micros()
}
pub fn format_now_utc(fmt: &str) -> String {
Utc::now().format(fmt).to_string()
}
pub fn format_now_local(fmt: &str) -> String {
Local::now().format(fmt).to_string()
}
pub fn format_timestamp_utc(ts_seconds: i64, fmt: &str) -> Option<String> {
Utc.timestamp_opt(ts_seconds, 0)
.single()
.map(|dt: DateTime<Utc>| dt.format(fmt).to_string())
}
pub fn format_timestamp_local(ts_seconds: i64, fmt: &str) -> Option<String> {
Local
.timestamp_opt(ts_seconds, 0)
.single()
.map(|dt| dt.format(fmt).to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn now_millis_is_close_to_chrono() {
let mine = now_millis();
let chrono_now = Utc::now().timestamp_millis();
assert!((chrono_now - mine).abs() < 1000);
}
#[test]
fn now_seconds_is_close_to_chrono() {
let mine = now_seconds();
let chrono_now = Utc::now().timestamp();
assert!((chrono_now - mine).abs() <= 1);
}
#[test]
fn format_timestamp_utc_known_value() {
let s = format_timestamp_utc(1_704_067_200, "%Y-%m-%d %H:%M:%S").unwrap();
assert_eq!(s, "2024-01-01 00:00:00");
}
#[test]
fn format_timestamp_utc_rejects_out_of_range() {
assert!(format_timestamp_utc(i64::MAX, "%Y").is_none());
}
#[test]
fn format_now_utc_produces_expected_length() {
let s = format_now_utc("%Y-%m-%dT%H:%M:%SZ");
assert_eq!(s.len(), 20);
assert!(s.ends_with('Z'));
}
}