Skip to main content

deep_time/alloc_parse/
parse_duration.rs

1use crate::{
2    Dt, DtErr, DtErrKind, Lang, Scale, an_err, natural_duration_to_iso, natural_duration_to_span,
3};
4use alloc::string::String;
5
6impl Dt {
7    /// Parses duration strings with three clean priority tiers:
8    ///
9    /// 1. Strict ISO 8601
10    /// 2. Common natural-language formats
11    /// 3. Legacy bare number, supports decimals → fractional milliseconds
12    ///
13    /// Returns a [`Dt`].
14    pub fn from_duration_str(s: &str, lang: Lang) -> Result<Dt, DtErr> {
15        if s.is_empty() {
16            return Err(an_err!(DtErrKind::Incomplete, "empty"));
17        }
18
19        if Dt::looks_like_iso(s) {
20            return Dt::from_iso_duration(s).map_err(|e| {
21                an_err!(
22                    DtErrKind::InvalidInput,
23                    "iso: {}",
24                    s => e
25                )
26            });
27        }
28
29        if let Ok(dur) = natural_duration_to_span(s, lang, true) {
30            return Ok(dur);
31        }
32
33        if let Ok(ms) = s.parse::<f64>() {
34            if !ms.is_finite() {
35                return Err(an_err!(DtErrKind::OutOfRange, "{}", s));
36            }
37            let nanos = (ms * 1_000_000.0).round() as i128;
38            let span = Dt::from_ns(nanos, Scale::TAI);
39            return Ok(span);
40        }
41
42        Err(an_err!(DtErrKind::InvalidInput, "{}", s))
43    }
44
45    /// Converts a natural language duration into an ISO duration.
46    pub fn natural_to_iso(s: &str, lang: Lang) -> Result<String, DtErr> {
47        match natural_duration_to_iso(s, lang, true) {
48            Ok(iso) => Ok(iso),
49            Err(e) => Err(an_err!(
50                DtErrKind::InvalidInput,
51                "{}",
52                s => e
53            )),
54        }
55    }
56}