chrono_node/common/
merge_date_range.rs1use crate::calculation::duration::{add_duration, Duration, DurationUnit};
6use crate::common::abstract_refiners::MergingRefiner;
7use crate::core::components::Component;
8use crate::core::context::ParsingContext;
9use crate::core::js_date::JsDate;
10use crate::core::regex::JsRegex;
11use crate::core::result::ParsingResult;
12
13pub trait MergeDateRangePattern: Send + Sync {
15 fn pattern_between(&self) -> &JsRegex;
16}
17
18pub struct MergeDateRange<P>(pub P);
19
20fn gt(a: JsDate, b: JsDate) -> bool {
22 matches!((a.get_time(), b.get_time()), (Some(a), Some(b)) if a > b)
23}
24
25fn plus(date: JsDate, unit: DurationUnit, amount: f64) -> JsDate {
26 add_duration(date, &mut Duration::from_pairs(&[(unit, amount)]))
27}
28
29impl<P: MergeDateRangePattern> MergingRefiner for MergeDateRange<P> {
30 fn should_merge_results(
31 &self,
32 text_between: &str,
33 current: &ParsingResult,
34 next: &ParsingResult,
35 _context: &ParsingContext,
36 ) -> bool {
37 current.end.is_none() && next.end.is_none() && self.0.pattern_between().is_match(text_between)
38 }
39
40 fn merge_results(
41 &self,
42 text_between: &str,
43 current: ParsingResult,
44 next: ParsingResult,
45 _context: &ParsingContext,
46 ) -> ParsingResult {
47 let (mut from, mut to) = (current, next);
48 if !from.start.is_only_weekday_component() && !to.start.is_only_weekday_component() {
49 for key in to.start.get_certain_components() {
50 if !from.start.is_certain(key) {
51 from.start.imply(key, to.start.get_or_zero(key));
52 }
53 }
54 for key in from.start.get_certain_components() {
55 if !to.start.is_certain(key) {
56 to.start.imply(key, from.start.get_or_zero(key));
57 }
58 }
59 }
60
61 if gt(from.start.date(), to.start.date()) {
62 let mut from_date = from.start.date();
63 let mut to_date = to.start.date();
64 if to.start.is_only_weekday_component() && gt(plus(to_date, DurationUnit::Day, 7.0), from_date) {
65 to_date = plus(to_date, DurationUnit::Day, 7.0);
66 to.start.imply(Component::Day, to_date.get_date());
67 to.start.imply(Component::Month, to_date.get_month() + 1);
68 to.start.imply(Component::Year, to_date.get_full_year());
69 } else if from.start.is_only_weekday_component() && gt(to_date, plus(from_date, DurationUnit::Day, -7.0)) {
70 from_date = plus(from_date, DurationUnit::Day, -7.0);
71 from.start.imply(Component::Day, from_date.get_date());
72 from.start.imply(Component::Month, from_date.get_month() + 1);
73 from.start.imply(Component::Year, from_date.get_full_year());
74 } else if to.start.is_date_with_unknown_year() && gt(plus(to_date, DurationUnit::Year, 1.0), from_date) {
75 to_date = plus(to_date, DurationUnit::Year, 1.0);
76 to.start.imply(Component::Year, to_date.get_full_year());
77 } else if from.start.is_date_with_unknown_year() && gt(to_date, plus(from_date, DurationUnit::Year, -1.0)) {
78 from_date = plus(from_date, DurationUnit::Year, -1.0);
79 from.start.imply(Component::Year, from_date.get_full_year());
80 } else {
81 std::mem::swap(&mut from, &mut to);
82 }
83 }
84
85 let mut result = from.js_clone();
86 result.start = from.start.clone();
87 result.end = Some(to.start.clone());
88 result.index = from.index.min(to.index);
89 result.text = if from.index < to.index {
90 format!("{}{}{}", from.text, text_between, to.text)
91 } else {
92 format!("{}{}{}", to.text, text_between, from.text)
93 };
94 result
95 }
96}