Skip to main content

whichtime_sys/parsers/en/
casual_date.rs

1//! Casual date parser: now, today, tomorrow, yesterday, etc.
2
3use std::sync::LazyLock;
4
5use crate::components::Component;
6use crate::context::ParsingContext;
7use crate::dictionaries::CasualDateType;
8use crate::dictionaries::en::get_casual_date;
9use crate::error::Result;
10use crate::parsers::Parser;
11use crate::results::ParsedResult;
12use crate::scanner::TokenType;
13use chrono::{Datelike, Duration, Timelike};
14use regex::Regex;
15
16static PATTERN: LazyLock<Regex> = LazyLock::new(|| {
17    Regex::new(r"(?i)\b(now|today|tonight|tomorrow|overmorrow|tmr|tmrw|yesterday)\b").unwrap()
18});
19
20/// Parser for English casual date expressions such as "tomorrow".
21pub struct CasualDateParser;
22
23impl Parser for CasualDateParser {
24    fn name(&self) -> &'static str {
25        "CasualDateParser"
26    }
27
28    fn should_apply(&self, context: &ParsingContext) -> bool {
29        context.has_token_type(TokenType::CasualDate)
30    }
31
32    fn parse(&self, context: &ParsingContext) -> Result<Vec<ParsedResult>> {
33        let mut results = Vec::new();
34
35        // for mat in PATTERN.find_iter(context.text) {
36        for mat in PATTERN.find_iter(context.text) {
37            let matched_text = mat.as_str();
38            let lower = matched_text.to_lowercase();
39            let index = mat.start();
40
41            let mut components = context.create_components();
42            let ref_date = context.reference.instant;
43
44            let Some(casual_type) = get_casual_date(&lower) else {
45                continue;
46            };
47
48            match casual_type {
49                CasualDateType::Now => {
50                    components.assign(Component::Year, ref_date.year());
51                    components.assign(Component::Month, ref_date.month() as i32);
52                    components.assign(Component::Day, ref_date.day() as i32);
53                    components.assign(Component::Hour, ref_date.hour() as i32);
54                    components.assign(Component::Minute, ref_date.minute() as i32);
55                    components.assign(Component::Second, ref_date.second() as i32);
56                }
57                CasualDateType::Today => {
58                    components.assign(Component::Year, ref_date.year());
59                    components.assign(Component::Month, ref_date.month() as i32);
60                    components.assign(Component::Day, ref_date.day() as i32);
61                }
62                CasualDateType::Tonight => {
63                    components.assign(Component::Year, ref_date.year());
64                    components.assign(Component::Month, ref_date.month() as i32);
65                    components.assign(Component::Day, ref_date.day() as i32);
66                    components.imply(Component::Hour, 22);
67                }
68                CasualDateType::Tomorrow => {
69                    let tomorrow = ref_date + Duration::days(1);
70                    components.assign(Component::Year, tomorrow.year());
71                    components.assign(Component::Month, tomorrow.month() as i32);
72                    components.assign(Component::Day, tomorrow.day() as i32);
73                }
74                CasualDateType::Yesterday => {
75                    let yesterday = ref_date - Duration::days(1);
76                    components.assign(Component::Year, yesterday.year());
77                    components.assign(Component::Month, yesterday.month() as i32);
78                    components.assign(Component::Day, yesterday.day() as i32);
79                }
80                CasualDateType::Overmorrow => {
81                    let day_after = ref_date + Duration::days(2);
82                    components.assign(Component::Year, day_after.year());
83                    components.assign(Component::Month, day_after.month() as i32);
84                    components.assign(Component::Day, day_after.day() as i32);
85                }
86                CasualDateType::DayBeforeYesterday => {
87                    let day_before = ref_date - Duration::days(2);
88                    components.assign(Component::Year, day_before.year());
89                    components.assign(Component::Month, day_before.month() as i32);
90                    components.assign(Component::Day, day_before.day() as i32);
91                }
92                CasualDateType::ThisMorning => {
93                    components.assign(Component::Year, ref_date.year());
94                    components.assign(Component::Month, ref_date.month() as i32);
95                    components.assign(Component::Day, ref_date.day() as i32);
96                    components.imply(Component::Hour, 6);
97                }
98                CasualDateType::ThisAfternoon => {
99                    components.assign(Component::Year, ref_date.year());
100                    components.assign(Component::Month, ref_date.month() as i32);
101                    components.assign(Component::Day, ref_date.day() as i32);
102                    components.imply(Component::Hour, 15);
103                }
104                CasualDateType::ThisEvening => {
105                    components.assign(Component::Year, ref_date.year());
106                    components.assign(Component::Month, ref_date.month() as i32);
107                    components.assign(Component::Day, ref_date.day() as i32);
108                    components.imply(Component::Hour, 20);
109                }
110            }
111
112            results.push(context.create_result(
113                index,
114                index + matched_text.len(),
115                components,
116                None,
117            ));
118        }
119
120        Ok(results)
121    }
122}