whichtime_sys/parsers/en/
casual_date.rs1use 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
20pub 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) {
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}