use chrono::{DateTime, Duration, Utc};
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct Cron {
pub minutes: Option<u32>,
pub hours: Option<u32>,
pub day_of_month: Option<u32>,
pub month: Option<u32>,
pub day_of_week: Option<u32>,
}
macro_rules! cron_meth {
($field:ident) => {
pub fn $field(self, m: u32) -> Cron {
let mut rv = self.clone();
rv.$field = Some(m);
rv
}
};
}
impl Cron {
pub fn new() -> Cron {
Cron::default()
}
cron_meth!(minutes);
cron_meth!(hours);
cron_meth!(day_of_month);
cron_meth!(month);
cron_meth!(day_of_week);
pub fn next_run(&self, cur: DateTime<Utc>) -> i64 {
use chrono::prelude::*;
let mut next = cur
.clone()
.with_second(0)
.unwrap()
.with_nanosecond(0)
.unwrap()
+ Duration::minutes(1);
let mut done = false;
while !done {
if let Some(cron_minute) = self.minutes {
if next.minute() != cron_minute {
if next.minute() > cron_minute {
next = next + Duration::hours(1);
}
next = next.with_minute(cron_minute).unwrap();
continue;
}
}
if let Some(cron_hour) = self.hours {
if next.hour() != cron_hour {
if next.hour() > cron_hour {
next = next.with_hour(cron_hour).unwrap().with_minute(0).unwrap()
+ Duration::days(1);
continue;
}
next = next.with_hour(cron_hour).unwrap().with_minute(0).unwrap();
continue;
}
}
if let Some(cron_day_of_week) = self.day_of_week {
let next_day_of_week = next.weekday().num_days_from_sunday();
if next_day_of_week != cron_day_of_week {
let mut delta_days = cron_day_of_week as i32 - next_day_of_week as i32;
if delta_days < 0 {
delta_days += 7;
}
next = next.with_hour(0).unwrap().with_minute(0).unwrap()
+ Duration::days(delta_days as i64);
continue;
}
}
if let Some(cron_day) = self.day_of_month {
if next.day() != cron_day {
if next.day() > cron_day || next.with_day(cron_day).is_none() {
next = next
.with_day(1)
.unwrap()
.with_hour(0)
.unwrap()
.with_minute(0)
.unwrap();
next = next
.with_month(next.month() + 1)
.unwrap_or_else(|| next.with_month(1).unwrap());
continue;
}
next = next
.with_hour(0)
.unwrap()
.with_minute(0)
.unwrap()
.with_day(cron_day)
.unwrap();
continue;
}
}
if let Some(cron_month) = self.month {
if next.month() != cron_month {
if next.month() > cron_month {
next = next
.with_month(12 - next.month() + cron_month)
.unwrap()
.with_day(1)
.unwrap()
.with_hour(0)
.unwrap()
.with_minute(0)
.unwrap();
continue;
}
next = next
.with_month(cron_month)
.unwrap()
.with_day(1)
.unwrap()
.with_hour(0)
.unwrap()
.with_minute(0)
.unwrap();
continue;
}
}
done = true;
}
next.timestamp_millis()
}
}