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