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
use crate::{CronInterval, Specification};
use chrono::{DateTime, Duration, TimeZone};
use std::rc::Rc;
#[derive(Clone)]
pub struct CronIntervalIterator<Tz: TimeZone, S: Specification<DateTime<Tz>>> {
timezone: Tz,
curr: DateTime<Tz>,
next: DateTime<Tz>,
cron_interval: Rc<CronInterval<Tz, S>>,
}
impl<Tz: TimeZone, S: Specification<DateTime<Tz>>> CronIntervalIterator<Tz, S> {
pub fn new(timezone: Tz, curr: DateTime<Tz>, next: DateTime<Tz>, cron_interval: Rc<CronInterval<Tz, S>>) -> Self {
Self {
timezone,
curr,
next,
cron_interval,
}
}
}
impl<Tz: TimeZone, S: Specification<DateTime<Tz>>> Iterator for CronIntervalIterator<Tz, S> {
type Item = DateTime<Tz>;
fn next(&mut self) -> Option<Self::Item> {
self.curr = self.next.clone();
self.next = self.next.clone() + Duration::minutes(1);
match self.end_value() {
None => {
self.proceed_next();
let curr: DateTime<Tz> = self.curr.clone();
Some(curr)
}
Some(end) => {
if end >= self.curr {
self.proceed_next();
let curr: DateTime<Tz> = self.curr.clone();
Some(curr)
} else {
None
}
}
}
}
}
impl<Tz: TimeZone, S: Specification<DateTime<Tz>>> CronIntervalIterator<Tz, S> {
pub fn timezone(&self) -> &Tz {
&self.timezone
}
pub fn cron_interval(&self) -> Rc<CronInterval<Tz, S>> {
self.cron_interval.clone()
}
fn end_value(&self) -> Option<DateTime<Tz>> {
if self.cron_interval.underlying.has_upper_limit() {
let timestamp = self.cron_interval.underlying.as_upper_limit().as_value().unwrap();
let date_time = self.timezone.timestamp_millis_opt(*timestamp).unwrap();
Some(date_time)
} else {
None
}
}
fn proceed_next(&mut self) {
while !self.cron_interval.cron_specification.is_satisfied_by(&self.curr) {
self.curr = self.next.clone();
self.next = self.next.clone() + Duration::minutes(1);
}
}
}
#[cfg(test)]
mod tests {
use chrono::{TimeZone, Utc};
use intervals_rs::LimitValue;
use crate::{CronInterval, CronParser, CronSpecification};
#[test]
fn test_iterator() {
let dt = Utc.with_ymd_and_hms(2021, 1, 1, 1, 1, 0).unwrap();
let expr = CronParser::parse("0-59/30 0-23/2 * * *").unwrap();
let interval = CronInterval::new(
LimitValue::Limit(dt),
LimitValue::Limitless,
CronSpecification::new(expr),
);
let itr = interval.iter(Utc);
itr.take(5).for_each(|e| println!("{:?}", e));
}
}