Skip to main content

deep_time/time_parts/
from_str.rs

1use crate::{DtErr, DtErrKind, Offset, TimeParts, an_err, parser::Parser};
2
3impl TimeParts {
4    pub fn from_str(
5        fmt: &str,
6        input: &str,
7        inp_can_end_before_fmt: bool,
8        fmt_can_end_before_inp: bool,
9        allow_partial_date: bool,
10    ) -> Result<TimeParts, DtErr> {
11        let mut tm = TimeParts::new_utc();
12        let mut parser = Parser::new(
13            fmt.as_bytes(),
14            input.as_bytes(),
15            &mut tm,
16            inp_can_end_before_fmt,
17        );
18        parser.parse()?;
19        if parser.inp.is_empty() || fmt_can_end_before_inp {
20            // All input consumed → finalize
21            tm.finish(allow_partial_date)?;
22            Ok(tm)
23        } else {
24            // Trailing characters remain
25            Err(an_err!(DtErrKind::TrailingCharacters))
26        }
27    }
28
29    pub fn finish(&mut self, allow_partial_date: bool) -> core::result::Result<&mut Self, DtErr> {
30        if self.unix_timestamp_seconds.is_some() {
31            if self.hour.is_none() {
32                self.hour = Some(0);
33            }
34            if self.minute.is_none() {
35                self.minute = Some(0);
36            }
37            if self.second.is_none() {
38                self.second = Some(0);
39            }
40            if self.attos.is_none() {
41                self.attos = Some(0);
42            }
43            if self.offset.is_none() {
44                self.offset = Some(Offset::Utc);
45            }
46            return Ok(self);
47        }
48
49        // Sensible defaults for time components (most tests expect a full datetime)
50        if self.hour.is_none() {
51            self.hour = Some(0);
52        }
53        if self.minute.is_none() {
54            self.minute = Some(0);
55        }
56        if let Some(sec) = self.second {
57            if sec == 60 {
58                self.is_leap_second = true;
59            } else if sec > 60 {
60                return Err(an_err!(DtErrKind::OutOfRange, "seconds (0..=60): {}", sec));
61            }
62        } else {
63            self.second = Some(0);
64        }
65        if self.attos.is_none() {
66            self.attos = Some(0);
67        }
68        if self.offset.is_none() {
69            self.offset = Some(Offset::Utc);
70        }
71
72        let has_calendar_date = if allow_partial_date {
73            if self.day.is_none() {
74                self.day = Some(1);
75            }
76            if self.month.is_none() {
77                self.month = Some(1);
78            }
79            self.year.is_some()
80        } else {
81            self.year.is_some() && self.month.is_some() && self.day.is_some()
82        };
83        let has_ordinal_date = self.year.is_some() && self.day_of_year.is_some();
84        let has_iso_week_date = self.iso_week_year.is_some() && self.iso_week.is_some();
85
86        if !has_calendar_date && !has_ordinal_date && !has_iso_week_date {
87            return Err(an_err!(DtErrKind::Incomplete));
88        }
89
90        Ok(self)
91    }
92}