1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
use {
crate::*,
lazy_regex::{regex, regex_is_match},
};
#[derive(Debug, Clone, Copy)]
pub enum DateFilter {
After(Date),
Before(Date),
Not(Date),
Precise(Date),
Range(Date, Date),
}
impl DateFilter {
pub fn new(
s: &str,
default_year: Option<u16>,
default_month: Option<u8>,
) -> Result<Self, DateParseError> {
if let Some(s) = s.strip_prefix('>') {
return Ok(Self::After(
Date::with_implicit(s, default_year, default_month)?
));
}
if let Some(s) = s.strip_prefix('<') {
return Ok(Self::Before(
Date::with_implicit(s, default_year, default_month)?
));
}
if let Some(s) = s.strip_prefix('!') {
return Ok(Self::Not(
Date::with_implicit(s, default_year, default_month)?
));
}
let mut tokens = s.split('-');
Ok(match (tokens.next(), tokens.next()) {
(Some(a), Some(b)) => Self::Range(
Date::with_implicit(a, default_year, default_month)?,
Date::with_implicit(b, default_year, default_month)?,
),
(Some(a), None) => {
if regex_is_match!(r#"^(\d{4})$"#, a) {
let year = a.parse()?;
Self::Range(
Date::new(year, 1, 1)?,
Date::new(year, 12, 31)?,
)
} else if let Some(captures) = regex!(r#"^(\d{4})/(\d\d)$"#).captures(a) {
let year = captures[1].parse()?;
let month = captures[2].parse()?;
Self::Range(
Date::new(year, month, 1)?,
Date::new(year, month, 31)?,
)
} else {
Self::Precise(
Date::with_implicit(a, default_year, default_month)?,
)
}
}
_ => unsafe { std::hint::unreachable_unchecked() },
})
}
pub fn contains(self, candidate: Date) -> bool {
match self {
Self::After(date) => date < candidate,
Self::Before(date) => date > candidate,
Self::Not(date) => date != candidate,
Self::Precise(date) => date == candidate,
Self::Range(a, b) => a <= candidate && candidate <= b,
}
}
}
#[cfg(test)]
mod date_filter_tests {
use super::*;
#[test]
fn test_date_filter_fully_defined_range() {
let df = DateFilter::new("2021/01/03-2021/02/15", None, None).unwrap();
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 02, 01).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 02, 16).unwrap()), false);
}
#[test]
fn test_date_filter_precise_date() {
let df = DateFilter::new("2021/02/15", Some(2021), None).unwrap();
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 02, 16).unwrap()), false);
}
#[test]
fn test_date_filter_not_date() {
let df = DateFilter::new("!2021/02/15", Some(2021), None).unwrap();
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 16).unwrap()), true);
}
#[test]
fn test_date_filter_after_date_implicit_year() {
let df = DateFilter::new(">02/15", Some(2021), None).unwrap();
assert_eq!(df.contains(Date::new(2020, 11, 12).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 16).unwrap()), true);
}
#[test]
fn test_date_filter_after_date() {
let df = DateFilter::new(">2021/02/15", Some(2021), None).unwrap();
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 16).unwrap()), true);
}
#[test]
fn test_date_filter_before_date() {
let df = DateFilter::new("<2021/02/15", Some(2021), None).unwrap();
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 16).unwrap()), false);
}
#[test]
fn test_date_filter_default_year() {
let df = DateFilter::new("02/15", Some(2021), Some(02)).unwrap();
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 02, 16).unwrap()), false);
}
#[test]
fn test_date_filter_default_month_year() {
let df = DateFilter::new("15", Some(2021), Some(02)).unwrap();
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 02, 16).unwrap()), false);
}
#[test]
fn test_date_filter_month() {
let df = DateFilter::new("2021/02", Some(2021), Some(02)).unwrap();
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 03, 01).unwrap()), false);
}
#[test]
fn test_date_filter_year() {
let df = DateFilter::new("2021", Some(2021), Some(02)).unwrap();
assert_eq!(df.contains(Date::new(2020, 12, 28).unwrap()), false);
assert_eq!(df.contains(Date::new(2021, 01, 28).unwrap()), true);
assert_eq!(df.contains(Date::new(2021, 02, 15).unwrap()), true);
assert_eq!(df.contains(Date::new(2022, 03, 01).unwrap()), false);
}
}