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