imsg_session/util.rs
1//! Shared datetime utilities: MAP timestamp parsing and epoch-millisecond display.
2
3use chrono::{DateTime, NaiveDateTime, TimeZone, Utc};
4
5/// Converts a MAP basic-ISO datetime string (`YYYYMMDDTHHMMSS[±HHMM]`) to epoch milliseconds.
6///
7/// Parses only the first 15 characters; timezone suffix is ignored and the value is treated
8/// as UTC. Returns `None` if the string is shorter than 15 bytes or fails to parse.
9#[must_use]
10pub fn datetime_to_ms(s: &str) -> Option<i64> {
11 let truncated = s.get(..15)?;
12 let naive = NaiveDateTime::parse_from_str(truncated, "%Y%m%dT%H%M%S").ok()?;
13 Some(Utc.from_utc_datetime(&naive).timestamp_millis())
14}
15
16/// Formats epoch milliseconds as `YYYY-MM-DD HH:MM` in local time.
17///
18/// Returns `"?"` for timestamps outside the representable range.
19#[must_use]
20pub fn ms_to_display(ms: i64) -> String {
21 DateTime::from_timestamp_millis(ms).map_or_else(
22 || "?".to_owned(),
23 |dt| dt.with_timezone(&chrono::Local).format("%Y-%m-%d %H:%M").to_string(),
24 )
25}
26
27/// Current epoch milliseconds via `chrono::Utc`.
28#[must_use]
29pub fn now_ms() -> i64 {
30 Utc::now().timestamp_millis()
31}