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
mod unit;
pub use self::unit::UnitSchedule;
use ::error::CronParseResult;
use ::parser::Parser;
use chrono::*;
use std::u32;
pub struct CronSchedule {
pub expression: String,
pub seconds: Option<UnitSchedule>,
pub minutes: UnitSchedule,
pub hours: UnitSchedule,
pub days_of_month: UnitSchedule,
pub months: UnitSchedule,
pub days_of_week: UnitSchedule,
pub years: UnitSchedule,
}
pub struct CronScheduleIterator<'a> {
schedule: &'a CronSchedule,
previous_datetime: Option<DateTime<UTC>>
}
impl <'a> Iterator for CronScheduleIterator<'a> {
type Item = DateTime<UTC>;
fn next(&mut self) -> Option<DateTime<UTC>> {
let previous_datetime = match self.previous_datetime {
Some(datetime) => datetime,
None => UTC::now()
};
let next_datetime = self.schedule.next_utc_after(&previous_datetime);
self.previous_datetime = next_datetime;
next_datetime
}
}
impl CronSchedule {
pub fn parse<A>(expression: A) -> CronParseResult<CronSchedule> where A : AsRef<str> {
let parser = Parser::new();
parser.parse(expression)
}
pub fn upcoming<'a>(&'a self) -> CronScheduleIterator<'a> {
CronScheduleIterator{
schedule: self,
previous_datetime: None
}
}
pub fn next_utc(&self) -> Option<DateTime<UTC>> {
let now : DateTime<UTC> = UTC::now();
self.next_utc_after(&now)
}
pub fn next_utc_after(&self, after: &DateTime<UTC>) -> Option<DateTime<UTC>> {
let datetime = after.clone() + Duration::minutes(1);
let mut year_range = self.years.range_iter(datetime.year() as u32, u32::MAX);
let second = None;
for year in &mut year_range {
let mut month_range = self.months.range_iter(1, 12);
for month in &mut month_range {
let mut day_range = self.days_of_month.range_iter(1, CronSchedule::days_in_month(month, year));
for day in &mut day_range {
let mut hour_range = self.hours.range_iter(0, 23);
for hour in &mut hour_range {
let mut minute_range = self.minutes.range_iter(0, 59);
for minute in &mut minute_range {
let candidate = UTC.ymd(year as i32, month, day).and_hms(hour, minute, second.unwrap_or(0));
if candidate <= datetime {
continue;
}
return Some(candidate);
}
}
}
}
}
None
}
fn is_leap_year(year: u32) -> bool {
let by_four = year % 4 == 0;
let by_hundred = year % 100 == 0;
let by_four_hundred = year % 400 == 0;
return by_four && ((!by_hundred) || by_four_hundred);
}
fn days_in_month(month: u32, year: u32) -> u32 {
let is_leap_year = CronSchedule::is_leap_year(year);
match month {
9 | 4 | 6 | 11 => 30,
2 if is_leap_year => 29,
2 => 28,
_ => 31
}
}
}