whichtime_sys/parsers/de/
time_unit_relative.rs1use crate::components::Component;
10use crate::context::ParsingContext;
11use crate::error::Result;
12use crate::parsers::Parser;
13use crate::results::ParsedResult;
14use crate::types::{Duration, add_duration};
15use chrono::{Datelike, Timelike};
16use fancy_regex::Regex;
17use std::sync::LazyLock;
18
19static PATTERN: LazyLock<Regex> = LazyLock::new(|| {
20 Regex::new(
21 r"(?i)(?<![a-zA-ZäöüÄÖÜß])(kommend(?:e[rnms]?)?|nächst(?:e[rnms]?)?|naechst(?:e[rnms]?)?|letzt(?:e[rnms]?)?|vorig(?:e[rnms]?)?|vergangen(?:e[rnms]?)?)\s+(woche|monat(?:s)?|quartal(?:s)?|jahr(?:es)?)\b"
22 ).unwrap()
23});
24
25const MODIFIER_GROUP: usize = 1;
26const UNIT_GROUP: usize = 2;
27
28pub struct DETimeUnitRelativeParser;
30
31impl DETimeUnitRelativeParser {
32 pub fn new() -> Self {
33 Self
34 }
35}
36
37impl Parser for DETimeUnitRelativeParser {
38 fn name(&self) -> &'static str {
39 "DETimeUnitRelativeParser"
40 }
41
42 fn should_apply(&self, _context: &ParsingContext) -> bool {
43 true
44 }
45
46 fn parse(&self, context: &ParsingContext) -> Result<Vec<ParsedResult>> {
47 let mut results = Vec::new();
48 let ref_date = context.reference.instant;
49
50 let mut start = 0;
51 while start < context.text.len() {
52 let search_text = &context.text[start..];
53 let captures = match PATTERN.captures(search_text) {
54 Ok(Some(caps)) => caps,
55 Ok(None) => break,
56 Err(_) => break,
57 };
58
59 let full_match = match captures.get(0) {
60 Some(m) => m,
61 None => break,
62 };
63
64 let match_start = start + full_match.start();
65 let match_end = start + full_match.end();
66
67 let modifier = captures
68 .get(MODIFIER_GROUP)
69 .map(|m| m.as_str().to_lowercase())
70 .unwrap_or_default();
71
72 let unit = captures
73 .get(UNIT_GROUP)
74 .map(|m| m.as_str().to_lowercase())
75 .unwrap_or_default();
76
77 let multiplier: f64 = if modifier.starts_with("kommend")
79 || modifier.starts_with("nächst")
80 || modifier.starts_with("naechst")
81 {
82 1.0
83 } else {
84 -1.0
85 };
86
87 let mut duration = Duration::new();
88
89 if unit.starts_with("woche") {
90 duration.week = Some(multiplier);
91 } else if unit.starts_with("monat") {
92 duration.month = Some(multiplier);
93 } else if unit.starts_with("quartal") {
94 duration.quarter = Some(multiplier);
95 } else if unit.starts_with("jahr") {
96 duration.year = Some(multiplier);
97 }
98
99 let target_date = add_duration(ref_date, &duration);
100
101 let mut components = context.create_components();
102 components.assign(Component::Year, target_date.year());
103 components.assign(Component::Month, target_date.month() as i32);
104 components.assign(Component::Day, target_date.day() as i32);
105 components.imply(Component::Hour, target_date.hour() as i32);
107 components.imply(Component::Minute, target_date.minute() as i32);
108 components.imply(Component::Second, target_date.second() as i32);
109
110 results.push(context.create_result(match_start, match_end, components, None));
111
112 start = match_end;
113 }
114
115 Ok(results)
116 }
117}
118
119impl Default for DETimeUnitRelativeParser {
120 fn default() -> Self {
121 Self::new()
122 }
123}