csvpp 0.6.1

Compile csv++ source code to a target spreadsheet format
Documentation
//! # `DateTime::TryFrom`
//!
//! Uniform date-handling
//!
use super::DateTime;
use crate::error::{BadInput, ParseError, ParseResult};
use crate::parser::{ast_lexer, cell_lexer, TokenInput};

const DATE_TIME: &[&str] = &[
    "%Y-%m-%d %H:%M:%S",
    "%m/%d/%Y %H:%M:%S",
    "%Y-%m-%d %H:%M",
    "%m/%d/%Y %H:%M",
];

const DATE: &[&str] = &["%y-%m-%d", "%m/%d/%y", "%Y-%m-%d", "%m/%d/%Y"];

const TIME: &[&str] = &["%H:%M:%S.%Z", "%H:%M:%S", "%H:%M"];

macro_rules! try_formats {
    ($input:ident, $formats:ident, $target:expr, $chrono_target:path) => {{
        for format in $formats {
            if let Ok(res) = $chrono_target($input.input(), format) {
                return Ok($target(res));
            }
        }
    }};
}

fn token_into(input: impl BadInput + TokenInput) -> ParseResult<DateTime> {
    try_formats!(
        input,
        DATE_TIME,
        DateTime::DateAndTime,
        chrono::NaiveDateTime::parse_from_str
    );
    try_formats!(
        input,
        DATE,
        DateTime::Date,
        chrono::NaiveDate::parse_from_str
    );
    try_formats!(
        input,
        TIME,
        DateTime::Time,
        chrono::NaiveTime::parse_from_str
    );

    Err(input.into_parse_error("Unable to parse date"))
}

impl TryFrom<ast_lexer::TokenMatch<'_>> for DateTime {
    type Error = ParseError;

    fn try_from(input: ast_lexer::TokenMatch) -> ParseResult<Self> {
        token_into(input)
    }
}

impl TryFrom<cell_lexer::TokenMatch> for DateTime {
    type Error = ParseError;

    fn try_from(input: cell_lexer::TokenMatch) -> ParseResult<Self> {
        token_into(input)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::parser::ast_lexer;
    use crate::test_utils::*;
    use crate::*;

    fn build_input(s: &str, source_code: ArcSourceCode) -> ast_lexer::TokenMatch {
        build_ast_token_match(s, source_code)
    }

    #[test]
    fn naive_date() {
        let source_code = build_source_code();

        assert_eq!(
            DateTime::try_from(build_input("10/22/2012", source_code.clone())).unwrap(),
            DateTime::Date(chrono::NaiveDate::from_ymd_opt(2012, 10, 22).unwrap()),
        );

        assert_eq!(
            DateTime::try_from(build_input("2012-10-22", source_code.clone())).unwrap(),
            DateTime::Date(chrono::NaiveDate::from_ymd_opt(2012, 10, 22).unwrap()),
        );
    }

    #[test]
    fn date_and_time() {
        assert_eq!(
            DateTime::try_from(build_input("10/22/2012 1:00", build_source_code())).unwrap(),
            DateTime::DateAndTime(
                chrono::NaiveDate::from_ymd_opt(2012, 10, 22)
                    .unwrap()
                    .and_hms_opt(1, 0, 0)
                    .unwrap()
            ),
        );
    }

    #[test]
    fn naive_time() {
        assert_eq!(
            DateTime::try_from(build_input("1:00", build_source_code())).unwrap(),
            DateTime::Time(chrono::NaiveTime::from_hms_opt(1, 0, 0).unwrap()),
        );
    }
}