reminder_cli/
cron_parser.rs

1use anyhow::{bail, Result};
2use cron::Schedule;
3use std::str::FromStr;
4
5/// Parse cron expression from either standard cron format or English description
6///
7/// Examples:
8/// - Standard: "0 0 9 * * *" (every day at 9am)
9/// - English: "every day at 9am", "every monday at 14:00", "every hour"
10pub fn parse_cron(input: &str) -> Result<String> {
11    let input = input.trim();
12
13    // First try as standard cron expression
14    if Schedule::from_str(input).is_ok() {
15        return Ok(input.to_string());
16    }
17
18    // Try to parse as English description
19    match english_to_cron::str_cron_syntax(input) {
20        Ok(cron_expr) => {
21            // Validate the generated cron expression
22            if Schedule::from_str(&cron_expr).is_ok() {
23                Ok(cron_expr)
24            } else {
25                bail!(
26                    "Generated invalid cron expression from '{}': {}",
27                    input,
28                    cron_expr
29                )
30            }
31        }
32        Err(_) => {
33            bail!(
34                "Invalid cron expression: {}\n\
35                \n\
36                Supported formats:\n\
37                - Standard cron: \"0 0 9 * * *\" (sec min hour day month weekday)\n\
38                - English: \"every day at 9am\", \"every monday at 14:00\", \"every hour\"\n\
39                \n\
40                English examples:\n\
41                - \"every minute\"\n\
42                - \"every hour\"\n\
43                - \"every day at 9am\"\n\
44                - \"every monday at 10:00\"\n\
45                - \"every weekday at 8:30\"\n\
46                - \"every 30 minutes\"",
47                input
48            )
49        }
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_standard_cron() {
59        let result = parse_cron("0 0 9 * * *");
60        assert!(result.is_ok());
61        assert_eq!(result.unwrap(), "0 0 9 * * *");
62    }
63
64    #[test]
65    fn test_english_cron() {
66        // These tests depend on the english-to-cron library behavior
67        let result = parse_cron("every day at 9am");
68        assert!(result.is_ok());
69    }
70}