bronzeflow_time/
schedule_time.rs1use crate::prelude::ScheduleExpr;
2use bronzeflow_utils::{debug, BronzeError};
3use chrono::{DateTime, Duration, Local, Utc};
4use cron::ScheduleIterator;
5use std::cmp::Ordering;
6use std::iter::Take;
7use std::str::FromStr;
8
9type InternalDateTime = DateTime<Utc>;
10
11#[allow(dead_code)]
12const DEFAULT_DATETIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S %z";
13
14#[derive(Debug, Clone)]
15pub struct ScheduleTime {
16 pub(crate) dt: InternalDateTime,
17}
18
19#[derive(Debug, Clone)]
20pub struct ScheduleTimeHolder {
21 pub(crate) expr: ScheduleExpr,
22 pub(crate) min_interval: Option<Duration>,
23 pub(crate) last_run: Option<ScheduleTime>,
24 pub(crate) next_run: Option<ScheduleTime>,
25}
26
27pub trait ScheduleTimeOp {
28 fn last_run(&self) -> Option<ScheduleTime>;
29
30 fn next_run(&self) -> Option<ScheduleTime>;
31
32 fn set_last_run(&mut self, t: &ScheduleTime) -> &mut Self;
33
34 fn set_next_run(&mut self, t: &ScheduleTime) -> &mut Self;
35}
36
37impl ScheduleTime {
38 pub fn new(dt: InternalDateTime) -> Self {
39 ScheduleTime { dt }
40 }
41 pub fn from_now() -> Self {
42 let local_time = Local::now();
43 let utc_time = DateTime::<Utc>::from_utc(local_time.naive_utc(), Utc);
44 ScheduleTime::new(utc_time)
45 }
46}
47
48impl From<InternalDateTime> for ScheduleTime {
49 fn from(dt: InternalDateTime) -> Self {
50 ScheduleTime::new(dt)
51 }
52}
53
54impl FromStr for ScheduleTime {
55 type Err = BronzeError;
56
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 InternalDateTime::from_str(s)
59 .map(InternalDateTime::into)
60 .map_err(BronzeError::new)
61 }
62}
63
64impl PartialEq<Self> for ScheduleTime {
65 fn eq(&self, other: &Self) -> bool {
66 self.dt == other.dt
67 }
68}
69
70impl PartialOrd for ScheduleTime {
71 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
72 self.dt.partial_cmp(&other.dt)
73 }
74}
75
76impl ScheduleTimeHolder {
77 pub fn new(expr: ScheduleExpr) -> Self {
78 ScheduleTimeHolder {
79 expr,
80 min_interval: None,
81 last_run: None,
82 next_run: None,
83 }
84 }
85
86 pub fn init(&mut self) {
87 let now = ScheduleTime::from_now();
88 match self.expr.clone() {
89 ScheduleExpr::Cron(c) => {
90 let mut times = c.after(&now.dt).take(21);
91 debug!("Now: {}", now.dt);
92 let next_run = times.next().unwrap();
93
94 let min_interval: Duration = times
96 .collect::<Vec<InternalDateTime>>()
97 .windows(2)
98 .map(|x| x[1] - x[0])
99 .min()
100 .unwrap();
101 debug!("min interval is: {}", min_interval.num_seconds());
102 self.min_interval = Some(min_interval);
103 self.next_run = Some(ScheduleTime::from(next_run));
104 },
105 _ => panic!(),
106 }
107 }
108
109 fn get_next_times(
110 &self,
111 n: usize,
112 from: &InternalDateTime,
113 ) -> Option<Take<ScheduleIterator<'_, Utc>>> {
114 match &self.expr {
115 ScheduleExpr::Cron(c) => Some(c.after(from).take(n)),
116 ScheduleExpr::Preset(_) => None,
117 }
118 }
119
120 pub fn cmp_and_to_next(&mut self, from: &ScheduleTime) -> bool {
121 if let Some(ref next_time) = self.next_run {
122 if from.dt >= next_time.dt {
123 debug!("from: {}, next_run: {}", from.dt, &next_time.dt);
124 let copy_next_run = next_time.clone();
125 self.last_run = Some(copy_next_run);
126 if let Some(mut it) = self.get_next_times(1, &next_time.dt) {
127 let new_time = it.next().unwrap();
128 debug!("set new time {}", new_time);
129 self.next_run = Some(ScheduleTime::from(new_time));
130 return true;
131 }
132 }
133 }
134 false
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use crate::prelude::ScheduleExpr;
141 use crate::schedule_time::ScheduleTimeHolder;
142 use std::str::FromStr;
143
144 #[test]
145 fn test_time_holder() {
146 let expr = ScheduleExpr::from_str("@daily").unwrap();
147
148 let mut s = ScheduleTimeHolder::new(expr);
149 s.init()
150 }
151}