flexible_time/
primitives.rs

1//! Parsing primitives
2
3use crate::error::ParsingError;
4use crate::timestamp::ParsedTimestamp;
5use time::{macros::format_description, parsing::Parsed};
6
7pub fn parse_format_opt<F>(
8    input: &[u8],
9    items: &[::time::format_description::FormatItem<'_>],
10    f: F,
11) -> Result<ParsedTimestamp, ParsingError>
12where
13    F: FnOnce(Parsed) -> Option<ParsedTimestamp>,
14{
15    let mut parsed = Parsed::new();
16
17    let result = parsed.parse_items(input, items)?;
18
19    if !result.is_empty() {
20        return Err(ParsingError::RemainingInformation);
21    }
22
23    f(parsed).ok_or(ParsingError::MissingInformation)
24}
25
26/// Parse year.
27pub fn parse_year(input: &[u8]) -> Result<ParsedTimestamp, ParsingError> {
28    let format = format_description!("[year]");
29
30    parse_format_opt(input, format, |parsed| {
31        Some(ParsedTimestamp::Year(parsed.year()?))
32    })
33}
34
35/// Parse year, and month.
36pub fn parse_year_month(input: &[u8]) -> Result<ParsedTimestamp, ParsingError> {
37    let format = format_description!("[year]-[month]");
38
39    parse_format_opt(input, format, |parsed| {
40        Some(ParsedTimestamp::YearMonth(parsed.year()?, parsed.month()?))
41    })
42}
43
44/// Parse year, month, and day.
45pub fn parse_year_month_day(input: &[u8]) -> Result<ParsedTimestamp, ParsingError> {
46    let format = format_description!("[year]-[month]-[day]");
47
48    parse_format_opt(input, format, |parsed| {
49        Some(ParsedTimestamp::YearMonthDay(
50            parsed.year()?,
51            parsed.month()?,
52            parsed.day()?,
53        ))
54    })
55}
56
57/// Parse year, month, day, and hour.
58pub fn parse_year_month_day_hour(input: &[u8]) -> Result<ParsedTimestamp, ParsingError> {
59    let format = format_description!("[year]-[month]-[day][first [T] [ ]][hour padding:none]");
60
61    parse_format_opt(input, format, |parsed| {
62        Some(ParsedTimestamp::YearMonthDayHour(
63            parsed.year()?,
64            parsed.month()?,
65            parsed.day()?,
66            parsed.hour_24()?,
67        ))
68    })
69}
70
71/// Parse year, month, day, hour, and minute.
72pub fn parse_year_month_day_hour_minute(input: &[u8]) -> Result<ParsedTimestamp, ParsingError> {
73    let format =
74        format_description!("[year]-[month]-[day][first [T] [ ]][hour padding:none]:[minute]");
75
76    parse_format_opt(input, format, |parsed| {
77        Some(ParsedTimestamp::YearMonthDayHourMinute(
78            parsed.year()?,
79            parsed.month()?,
80            parsed.day()?,
81            parsed.hour_24()?,
82            parsed.minute()?,
83        ))
84    })
85}
86
87/// Parse year, month, day, hour, minute, and second.
88pub fn parse_year_month_day_hour_minute_second(
89    input: &[u8],
90) -> Result<ParsedTimestamp, ParsingError> {
91    let format = format_description!(
92        "[year]-[month]-[day][first [T] [ ]][hour padding:none]:[minute]:[second]"
93    );
94
95    parse_format_opt(input, format, |parsed| {
96        Some(ParsedTimestamp::YearMonthDayHourMinuteSecond(
97            parsed.year()?,
98            parsed.month()?,
99            parsed.day()?,
100            parsed.hour_24()?,
101            parsed.minute()?,
102            parsed.second()?,
103        ))
104    })
105}
106
107#[cfg(test)]
108mod test {
109    use super::*;
110
111    #[test]
112    fn test_optional() {
113        let format =
114            format_description!("[year]-[month]-[day][first [T] [ ]][hour]:[minute]:[second]");
115        let mut parsed = Parsed::new();
116        parsed.parse_items(b"2023-01-01 12:34:56", &format).unwrap();
117        parsed.parse_items(b"2023-01-01T12:34:56", &format).unwrap();
118    }
119}