whichtime_sys/parsers/es/
casual_time.rs1use crate::components::Component;
9use crate::context::ParsingContext;
10use crate::error::Result;
11use crate::parsers::Parser;
12use crate::results::ParsedResult;
13use crate::scanner::TokenType;
14use crate::types::Meridiem;
15use chrono::{Datelike, Duration, Timelike};
16use fancy_regex::Regex;
17use std::sync::LazyLock;
18
19static PATTERN: LazyLock<Regex> = LazyLock::new(|| {
20 Regex::new(
21 r"(?i)(?:el\s+|la\s+)?(?:esta\s+)?(mediodía|mediodia|medianoche|mañana|manana|tarde|noche)(?=\W|$)"
22 ).unwrap()
23});
24
25pub struct ESCasualTimeParser;
27
28impl ESCasualTimeParser {
29 pub fn new() -> Self {
30 Self
31 }
32}
33
34impl Parser for ESCasualTimeParser {
35 fn name(&self) -> &'static str {
36 "ESCasualTimeParser"
37 }
38
39 fn should_apply(&self, context: &ParsingContext) -> bool {
40 context.has_token_type(TokenType::CasualTime)
41 }
42
43 fn parse(&self, context: &ParsingContext) -> Result<Vec<ParsedResult>> {
44 let mut results = Vec::new();
45 let ref_date = context.reference.instant;
46
47 let mut start = 0;
48 while start < context.text.len() {
49 let search_text = &context.text[start..];
50 let mat = match PATTERN.find(search_text) {
51 Ok(Some(m)) => m,
52 Ok(None) => break,
53 Err(_) => break,
54 };
55
56 let matched_text = mat.as_str();
57 let index = start + mat.start();
58
59 let caps = match PATTERN.captures(matched_text) {
60 Ok(Some(c)) => c,
61 Ok(None) => {
62 start = index + 1;
63 continue;
64 }
65 Err(_) => {
66 start = index + 1;
67 continue;
68 }
69 };
70
71 let time_word = caps
72 .get(1)
73 .map(|m| m.as_str().to_lowercase())
74 .unwrap_or_default();
75
76 let mut components = context.create_components();
77
78 let mut target_date = ref_date;
80
81 match time_word.as_str() {
82 "mediodía" | "mediodia" => {
83 components.assign(Component::Hour, 12);
84 components.assign(Component::Minute, 0);
85 components.assign(Component::Second, 0);
86 components.assign(Component::Meridiem, Meridiem::PM as i32);
87 }
88 "medianoche" => {
89 if ref_date.hour() >= 6 {
91 target_date = ref_date + Duration::days(1);
92 }
93 components.assign(Component::Hour, 0);
94 components.assign(Component::Minute, 0);
95 components.assign(Component::Second, 0);
96 }
97 "mañana" | "manana" => {
98 components.imply(Component::Hour, 6);
100 components.imply(Component::Minute, 0);
101 components.assign(Component::Meridiem, Meridiem::AM as i32);
102 }
103 "tarde" => {
104 components.imply(Component::Hour, 15);
105 components.imply(Component::Minute, 0);
106 components.assign(Component::Meridiem, Meridiem::PM as i32);
107 }
108 "noche" => {
109 components.imply(Component::Hour, 22);
110 components.imply(Component::Minute, 0);
111 components.assign(Component::Meridiem, Meridiem::PM as i32);
112 }
113 _ => continue,
114 }
115
116 components.assign(Component::Year, target_date.year());
118 components.assign(Component::Month, target_date.month() as i32);
119 components.assign(Component::Day, target_date.day() as i32);
120
121 results.push(context.create_result(
122 index,
123 index + matched_text.len(),
124 components,
125 None,
126 ));
127
128 start = index + matched_text.len();
129 }
130
131 Ok(results)
132 }
133}
134
135impl Default for ESCasualTimeParser {
136 fn default() -> Self {
137 Self::new()
138 }
139}