otell-core 0.3.0

Core shared models and query schemas for otell
Documentation
use std::time::Duration;

use chrono::{DateTime, Utc};

use crate::error::{OtellError, Result};

pub fn parse_time_or_relative(input: &str) -> Result<DateTime<Utc>> {
    if let Ok(ts) = DateTime::parse_from_rfc3339(input) {
        return Ok(ts.with_timezone(&Utc));
    }

    if let Ok(duration) = humantime::parse_duration(input) {
        return Ok(Utc::now()
            - chrono::Duration::from_std(duration).map_err(|e| {
                OtellError::Parse(format!("failed to parse duration to chrono: {e}"))
            })?);
    }

    Err(OtellError::Parse(format!(
        "expected RFC3339 time or duration, got {input}"
    )))
}

pub fn parse_duration_str(input: &str) -> Result<Duration> {
    humantime::parse_duration(input)
        .map_err(|e| OtellError::Parse(format!("invalid duration {input}: {e}")))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_rfc3339() {
        let ts = parse_time_or_relative("2026-01-01T00:00:00Z").unwrap();
        assert_eq!(ts.to_rfc3339(), "2026-01-01T00:00:00+00:00");
    }

    #[test]
    fn parses_duration() {
        let now = Utc::now();
        let ts = parse_time_or_relative("5m").unwrap();
        assert!(ts < now);
    }

    #[test]
    fn rejects_invalid() {
        assert!(parse_time_or_relative("nope").is_err());
    }
}