time_range_ext/time_range/
vec_range.rs1use time::OffsetDateTime;
2use crate::time_range::{TimeRange};
3use crate::time_range::time_range_ext::TimeRangeExt;
4
5impl TimeRangeExt for Vec<TimeRange> {
6 fn ends(&self) -> Vec<OffsetDateTime> {
7 self.iter().map(|t| t.end).collect()
8 }
9 fn starts(&self) -> Vec<OffsetDateTime> {
10 self.iter().map(|t| t.start).collect()
11 }
12
13 fn contains_ts(&self, ts: OffsetDateTime) -> bool {
14 self.iter().any(|t| t.start <= ts && ts <= t.end)
15 }
16
17 fn range_within_ts(&self, ts: OffsetDateTime) -> Option<&TimeRange> {
18 self.iter().find(|t| t.start <= ts && ts <= t.end)
19 }
20
21 fn overlaps(&self, other: &TimeRange) -> Option<&TimeRange> {
22 self.iter().find(|r| other.overlaps(r))
23 }
24
25 fn get_overlapping_range(&self, tr: TimeRange) -> Option<TimeRange> {
26 let range_start = self.range_within_ts(tr.start);
27 let range_end = self.range_within_ts(tr.end);
28
29 let within_range = self.overlaps(&tr);
30
31 match (range_start, range_end, within_range) {
32 (Some(start), Some(end), _) => {
33 if start.end != end.end {
36 Some(TimeRange {
37 start: tr.start,
38 end: start.end,
39 })
40 } else {
41 Some(TimeRange {
42 start: tr.start,
43 end: tr.end,
44 })
45 }
46 }
47 (Some(start), None, _) => Some(TimeRange {
48 start: tr.start,
49 end: start.end,
50 }),
51 (None, Some(end), _) => Some(TimeRange {
52 start: end.start,
53 end: tr.end,
54 }),
55 (None, None, Some(within)) => Some(*within),
56 (None, None, None) => None,
57 }
58 }
59
60 fn dedup_overlapping_ranges(mut self) -> Self {
61 if self.is_empty() {
62 return self;
63 }
64
65 self.sort_by(|a, b| a.start.cmp(&b.start));
66
67 let mut result = Vec::new();
68
69 let mut current_range = self[0];
70 for range in self.into_iter().skip(1) {
71 if current_range.overlaps(&range) {
72 current_range = current_range.merge(&range);
73 } else {
74 result.push(current_range);
75 current_range = range;
76 }
77 }
78 result.push(current_range);
79
80 result
81 }
82
83 fn times_between_contents(self, bounds: Option<TimeRange>) -> Self {
84 let mut times_between = vec![];
85 let mut windows = self.windows(2);
86
87 if self.len() == 1 {
88 if let Some(bounds) = bounds {
89 if self[0].end < bounds.end {
90 times_between.push(TimeRange {
91 start: self[0].end,
92 end: bounds.end,
93 });
94 }
95 }
96
97 return times_between;
98 }
99
100 while let Some(&[current, next]) = windows.next() {
101 if current.end == next.start {
102 continue;
103 }
104
105 let start = current.end;
106 let end = next.start;
107
108 times_between.push(TimeRange { start, end });
109 }
110
111 times_between
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use time::macros::datetime;
118 use crate::time_range::time_range_ext::TimeRangeExt;
119
120 #[test]
121 fn test_overlapping_range() {
122 let ranges = vec![
123 super::TimeRange {
124 start: time::OffsetDateTime::from_unix_timestamp(0).unwrap(),
125 end: time::OffsetDateTime::from_unix_timestamp(10).unwrap(),
126 },
127 super::TimeRange {
128 start: time::OffsetDateTime::from_unix_timestamp(15).unwrap(),
129 end: time::OffsetDateTime::from_unix_timestamp(20).unwrap(),
130 },
131 super::TimeRange {
132 start: time::OffsetDateTime::from_unix_timestamp(20).unwrap(),
133 end: time::OffsetDateTime::from_unix_timestamp(30).unwrap(),
134 },
135 ];
136
137 let tr = super::TimeRange {
138 start: time::OffsetDateTime::from_unix_timestamp(5).unwrap(),
139 end: time::OffsetDateTime::from_unix_timestamp(8).unwrap(),
140 };
141
142 let overlapping_range = ranges.get_overlapping_range(tr);
143
144 assert_eq!(
145 overlapping_range,
146 Some(super::TimeRange {
147 start: time::OffsetDateTime::from_unix_timestamp(5).unwrap(),
148 end: time::OffsetDateTime::from_unix_timestamp(8).unwrap(),
149 })
150 );
151
152 let tr = super::TimeRange {
153 start: time::OffsetDateTime::from_unix_timestamp(5).unwrap(),
154 end: time::OffsetDateTime::from_unix_timestamp(15).unwrap(),
155 };
156
157 let overlapping_range = ranges.get_overlapping_range(tr);
158
159 assert_eq!(
160 overlapping_range,
161 Some(super::TimeRange {
162 start: time::OffsetDateTime::from_unix_timestamp(5).unwrap(),
163 end: time::OffsetDateTime::from_unix_timestamp(10).unwrap(),
164 })
165 );
166
167 let ranges = vec![super::TimeRange {
168 start: datetime!(2024-04-21 23:10:15.502 UTC),
169 end: datetime!(2024-04-22 05:30:00.000 UTC),
170 }];
171
172 let tr = super::TimeRange {
173 start: datetime!(2024-04-20 16:25:25.632 UTC),
174 end: datetime!(2024-04-22 05:45:03.018 UTC),
175 };
176
177 assert_eq!(
178 ranges.get_overlapping_range(tr),
179 Some(super::TimeRange {
180 start: datetime!(2024-04-21 23:10:15.502 UTC),
181 end: datetime!(2024-04-22 05:30:00.000 UTC),
182 })
183 );
184 }
185
186 #[test]
187 fn test_deduping() {
188 let ranges = vec![
189 super::TimeRange {
190 start: time::OffsetDateTime::from_unix_timestamp(0).unwrap(),
191 end: time::OffsetDateTime::from_unix_timestamp(10).unwrap(),
192 },
193 super::TimeRange {
194 start: time::OffsetDateTime::from_unix_timestamp(5).unwrap(),
195 end: time::OffsetDateTime::from_unix_timestamp(15).unwrap(),
196 },
197 super::TimeRange {
198 start: time::OffsetDateTime::from_unix_timestamp(20).unwrap(),
199 end: time::OffsetDateTime::from_unix_timestamp(30).unwrap(),
200 },
201 ];
202
203 let deduped_ranges = ranges.dedup_overlapping_ranges();
204
205 assert_eq!(
206 deduped_ranges,
207 vec![
208 super::TimeRange {
209 start: time::OffsetDateTime::from_unix_timestamp(0).unwrap(),
210 end: time::OffsetDateTime::from_unix_timestamp(15).unwrap(),
211 },
212 super::TimeRange {
213 start: time::OffsetDateTime::from_unix_timestamp(20).unwrap(),
214 end: time::OffsetDateTime::from_unix_timestamp(30).unwrap(),
215 },
216 ]
217 );
218
219 let ranges = vec![
220 super::TimeRange {
221 start: time::OffsetDateTime::from_unix_timestamp(0).unwrap(),
222 end: time::OffsetDateTime::from_unix_timestamp(10).unwrap(),
223 },
224 super::TimeRange {
225 start: time::OffsetDateTime::from_unix_timestamp(5).unwrap(),
226 end: time::OffsetDateTime::from_unix_timestamp(15).unwrap(),
227 },
228 super::TimeRange {
229 start: time::OffsetDateTime::from_unix_timestamp(0).unwrap(),
230 end: time::OffsetDateTime::from_unix_timestamp(50).unwrap(),
231 },
232 super::TimeRange {
233 start: time::OffsetDateTime::from_unix_timestamp(20).unwrap(),
234 end: time::OffsetDateTime::from_unix_timestamp(30).unwrap(),
235 },
236 ];
237
238 let deduped_ranges = ranges.dedup_overlapping_ranges();
239
240 assert_eq!(
241 deduped_ranges,
242 vec![super::TimeRange {
243 start: time::OffsetDateTime::from_unix_timestamp(0).unwrap(),
244 end: time::OffsetDateTime::from_unix_timestamp(50).unwrap(),
245 },]
246 );
247 }
248}