deep_time/alloc_parse/
parse_duration.rs1use 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 pub fn from_str_duration(s: &str, lang: Lang) -> Result<Dt, DtErr> {
16 if s.is_empty() {
17 return Err(an_err!(DtErrKind::Incomplete, "empty"));
18 }
19
20 if Dt::looks_like_iso(s) {
21 return Dt::from_iso_duration(s).map_err(|e| {
22 an_err!(
23 DtErrKind::InvalidInput,
24 "iso: {}",
25 s => e
26 )
27 });
28 }
29
30 if let Ok(dur) = natural_duration_to_span(s, lang, true) {
31 return Ok(dur);
32 }
33
34 if let Ok(dur) = Dt::from_str_media_duration(s) {
35 return Ok(dur);
36 }
37
38 if let Ok(ms) = s.parse::<f64>() {
39 if !ms.is_finite() {
40 return Err(an_err!(DtErrKind::OutOfRange, "{}", s));
41 }
42 let nanos = (ms * 1_000_000.0).round() as i128;
43 let span = Dt::from_ns(nanos, Scale::TAI);
44 return Ok(span);
45 }
46
47 Err(an_err!(DtErrKind::InvalidInput, "{}", s))
48 }
49
50 pub fn natural_to_iso(s: &str, lang: Lang) -> Result<String, DtErr> {
52 match natural_duration_to_iso(s, lang, true) {
53 Ok(iso) => Ok(iso),
54 Err(e) => Err(an_err!(
55 DtErrKind::InvalidInput,
56 "{}",
57 s => e
58 )),
59 }
60 }
61
62 fn looks_like_iso(s: &str) -> bool {
66 let len = s.len();
67 if matches!(len, 0 | 1) {
68 return false;
69 }
70 let b = s.as_bytes();
71 let mut i = 0usize;
72 if matches!(b[0], b'+' | b'-') {
74 i += 1;
75 }
76 if !matches!(b[i], b'P' | b'p') {
78 return false;
79 }
80 i += 1;
81 let mut has_digit = false;
82 let mut has_designator = false;
83 while i < len {
84 match b[i] {
85 b'0'..=b'9' => has_digit = true,
86 b'.' | b',' => {} b'Y' | b'y' | b'M' | b'm' | b'W' | b'w' | b'D' | b'd' | b'T' | b't' | b'H'
88 | b'h' | b'S' | b's' => {
89 has_designator = true;
90 }
91 _ => return false, }
93
94 i += 1;
95 }
96 has_digit && has_designator
98 }
99}