Skip to main content

whichtime_sys/refiners/
merge_date_range.rs

1//! Merge date range refiner - combines date results separated by range connectors
2//!
3//! Handles patterns like:
4//! - "heute - nächsten Freitag" -> single result with start and end
5//! - "10. August - 22. August" -> single result with start and end
6
7use crate::context::ParsingContext;
8use crate::refiners::Refiner;
9use crate::results::ParsedResult;
10
11/// Refiner that converts adjacent date matches into a range result.
12pub struct MergeDateRangeRefiner;
13
14impl Refiner for MergeDateRangeRefiner {
15    fn refine(&self, context: &ParsingContext, results: Vec<ParsedResult>) -> Vec<ParsedResult> {
16        if results.len() < 2 {
17            return results;
18        }
19
20        let mut merged = Vec::with_capacity(results.len());
21        let mut i = 0;
22
23        while i < results.len() {
24            let current = &results[i];
25
26            // Check if next result exists and could be merged as a range
27            if i + 1 < results.len() {
28                let next = &results[i + 1];
29
30                // Check if they're separated by a range connector
31                let gap_start = current.end_index;
32                let gap_end = next.index;
33
34                if gap_end > gap_start {
35                    let gap = &context.text[gap_start..gap_end];
36                    let gap_trimmed = gap.trim();
37
38                    // Check for range connectors: "-", "–", "bis"
39                    let is_range_connector = gap_trimmed == "-"
40                        || gap_trimmed == "–"
41                        || gap_trimmed.eq_ignore_ascii_case("bis");
42
43                    if is_range_connector {
44                        // Both should be date-like results (not pure time)
45                        let current_has_date = current.start.get(crate::Component::Day).is_some()
46                            || current.start.get(crate::Component::Month).is_some();
47                        let next_has_date = next.start.get(crate::Component::Day).is_some()
48                            || next.start.get(crate::Component::Month).is_some();
49
50                        if current_has_date && next_has_date {
51                            // Merge them as a range
52                            let merged_result = ParsedResult::new(
53                                context.reference,
54                                current.index,
55                                &context.text[current.index..next.end_index],
56                                current.start,
57                                Some(next.start),
58                            );
59
60                            merged.push(merged_result);
61                            i += 2;
62                            continue;
63                        }
64                    }
65                }
66            }
67
68            merged.push(results[i].clone());
69            i += 1;
70        }
71
72        merged
73    }
74}