whichtime_sys/parsers/it/
casual_date.rs1use crate::components::Component;
9use crate::context::ParsingContext;
10use crate::error::Result;
11use crate::parsers::Parser;
12use crate::results::ParsedResult;
13use crate::types::Meridiem;
14use chrono::{Datelike, Duration, Timelike};
15use fancy_regex::Regex;
16use std::sync::LazyLock;
17
18static PATTERN: LazyLock<Regex> = LazyLock::new(|| {
19 Regex::new(
20 r"(?i)(?<![a-zA-ZàèéìòùÀÈÉÌÒÙ])(adesso|ora|oggi|domani|ieri|dopodomani|altroieri|l'altro\s+ieri|stamattina|stasera|stanotte)(?:\s+(mattina|pomeriggio|sera|notte))?(?:\s+(?:alle?\s+)?(\d{1,2})(?:[:\.](\d{2}))?)?(?=\W|$)"
21 ).unwrap()
22});
23
24const DATE_GROUP: usize = 1;
25const TIME_PERIOD_GROUP: usize = 2;
26const HOUR_GROUP: usize = 3;
27const MINUTE_GROUP: usize = 4;
28
29pub struct ITCasualDateParser;
31
32impl ITCasualDateParser {
33 pub fn new() -> Self {
34 Self
35 }
36}
37
38impl Parser for ITCasualDateParser {
39 fn name(&self) -> &'static str {
40 "ITCasualDateParser"
41 }
42
43 fn should_apply(&self, _context: &ParsingContext) -> bool {
44 true
45 }
46
47 fn parse(&self, context: &ParsingContext) -> Result<Vec<ParsedResult>> {
48 let mut results = Vec::new();
49 let ref_date = context.reference.instant;
50
51 let mut start = 0;
52 while start < context.text.len() {
53 let search_text = &context.text[start..];
54 let captures = match PATTERN.captures(search_text) {
55 Ok(Some(caps)) => caps,
56 Ok(None) => break,
57 Err(_) => break,
58 };
59
60 let full_match = match captures.get(0) {
61 Some(m) => m,
62 None => break,
63 };
64
65 let match_start = start + full_match.start();
66 let match_end = start + full_match.end();
67
68 let date_keyword = captures
69 .get(DATE_GROUP)
70 .map(|m| m.as_str().to_lowercase())
71 .unwrap_or_default();
72
73 let time_period = captures
74 .get(TIME_PERIOD_GROUP)
75 .map(|m| m.as_str().to_lowercase());
76
77 let mut components = context.create_components();
78 let target_date;
79
80 match date_keyword.as_str() {
82 "adesso" | "ora" => {
83 components.assign(Component::Year, ref_date.year());
84 components.assign(Component::Month, ref_date.month() as i32);
85 components.assign(Component::Day, ref_date.day() as i32);
86 components.assign(Component::Hour, ref_date.hour() as i32);
87 components.assign(Component::Minute, ref_date.minute() as i32);
88 components.assign(Component::Second, ref_date.second() as i32);
89 }
90 "oggi" => {
91 components.assign(Component::Year, ref_date.year());
92 components.assign(Component::Month, ref_date.month() as i32);
93 components.assign(Component::Day, ref_date.day() as i32);
94 }
95 "domani" => {
96 target_date = ref_date + Duration::days(1);
97 components.assign(Component::Year, target_date.year());
98 components.assign(Component::Month, target_date.month() as i32);
99 components.assign(Component::Day, target_date.day() as i32);
100 }
101 "ieri" => {
102 target_date = ref_date - Duration::days(1);
103 components.assign(Component::Year, target_date.year());
104 components.assign(Component::Month, target_date.month() as i32);
105 components.assign(Component::Day, target_date.day() as i32);
106 }
107 "dopodomani" => {
108 target_date = ref_date + Duration::days(2);
109 components.assign(Component::Year, target_date.year());
110 components.assign(Component::Month, target_date.month() as i32);
111 components.assign(Component::Day, target_date.day() as i32);
112 }
113 "altroieri" | "l'altro ieri" => {
114 target_date = ref_date - Duration::days(2);
115 components.assign(Component::Year, target_date.year());
116 components.assign(Component::Month, target_date.month() as i32);
117 components.assign(Component::Day, target_date.day() as i32);
118 }
119 "stamattina" => {
120 components.assign(Component::Year, ref_date.year());
121 components.assign(Component::Month, ref_date.month() as i32);
122 components.assign(Component::Day, ref_date.day() as i32);
123 components.imply(Component::Hour, 6);
124 components.assign(Component::Meridiem, Meridiem::AM as i32);
125 }
126 "stasera" | "stanotte" => {
127 components.assign(Component::Year, ref_date.year());
128 components.assign(Component::Month, ref_date.month() as i32);
129 components.assign(Component::Day, ref_date.day() as i32);
130 components.imply(Component::Hour, 22);
131 components.assign(Component::Meridiem, Meridiem::PM as i32);
132 }
133 _ => {
134 start = match_end;
135 continue;
136 }
137 }
138
139 if let Some(ref period) = time_period {
141 match period.as_str() {
142 "mattina" => {
143 components.imply(Component::Hour, 8);
144 components.assign(Component::Meridiem, Meridiem::AM as i32);
145 }
146 "pomeriggio" => {
147 components.imply(Component::Hour, 14);
148 components.assign(Component::Meridiem, Meridiem::PM as i32);
149 }
150 "sera" => {
151 components.imply(Component::Hour, 18);
152 components.assign(Component::Meridiem, Meridiem::PM as i32);
153 }
154 "notte" => {
155 components.imply(Component::Hour, 22);
156 components.assign(Component::Meridiem, Meridiem::PM as i32);
157 }
158 _ => {}
159 }
160 }
161
162 if let Some(hour_match) = captures.get(HOUR_GROUP) {
164 let hour: i32 = hour_match.as_str().parse().unwrap_or(0);
165 let minute: i32 = captures
166 .get(MINUTE_GROUP)
167 .map(|m| m.as_str().parse().unwrap_or(0))
168 .unwrap_or(0);
169
170 components.assign(Component::Hour, hour);
171 components.assign(Component::Minute, minute);
172
173 if hour >= 12 {
174 components.assign(Component::Meridiem, Meridiem::PM as i32);
175 } else {
176 components.assign(Component::Meridiem, Meridiem::AM as i32);
177 }
178 }
179
180 results.push(context.create_result(match_start, match_end, components, None));
181
182 start = match_end;
183 }
184
185 Ok(results)
186 }
187}
188
189impl Default for ITCasualDateParser {
190 fn default() -> Self {
191 Self::new()
192 }
193}