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