loglens_core/
time.rs

1// src/pro/time_parser.rs
2
3use chrono::{DateTime, Utc, TimeZone};
4use humantime::parse_duration;
5use serde_json::Value;
6use std::time::SystemTime;
7
8/// Parses a user-provided time string into a DateTime object.
9/// Handles both relative times ("1h ago") and absolute timestamps.
10pub fn parse_time_string(time_str: &str) -> Result<DateTime<Utc>, String> {
11    if time_str.to_lowercase() == "now" {
12        return Ok(Utc::now());
13    }
14
15    // Try parsing as a relative duration (e.g., "15m", "2h ago")
16    let clean_str = time_str.strip_suffix(" ago").unwrap_or(time_str);
17    if let Ok(duration) = parse_duration(clean_str) {
18        let now = SystemTime::now();
19        let target_time = now - duration;
20        return Ok(target_time.into());
21    }
22
23    // Try parsing as an absolute timestamp (RFC3339 / ISO 8601)
24    if let Ok(datetime) = DateTime::parse_from_rfc3339(time_str) {
25        return Ok(datetime.with_timezone(&Utc));
26    }
27
28    Err(format!("Could not parse time string: {}", time_str))
29}
30
31/// Extracts and parses a timestamp from a JSON log entry.
32/// Tries a list of common timestamp field names.
33pub fn extract_and_parse_timestamp(value: &Value) -> Option<DateTime<Utc>> {
34    const COMMON_KEYS: [&str; 3] = ["timestamp", "ts", "@timestamp"];
35
36    for key in COMMON_KEYS {
37        if let Some(ts_value) = value.get(key) {
38            if let Some(ts_str) = ts_value.as_str() {
39                // Parse string timestamp
40                if let Ok(datetime) = DateTime::parse_from_rfc3339(ts_str) {
41                    return Some(datetime.with_timezone(&Utc));
42                }
43            } else if let Some(ts_unix) = ts_value.as_i64() {
44                // Parse Unix timestamp (seconds)
45                if let Some(datetime) = Utc.timestamp_opt(ts_unix, 0).single() {
46                    return Some(datetime);
47                }
48            }
49        }
50    }
51    None
52}