1use crate::error::TypeError;
2use chrono::{DateTime, Utc};
3use cron::Schedule;
4use pyo3::prelude::*;
5use serde::{Deserialize, Serialize};
6use std::fmt;
7use std::str::FromStr;
8
9#[pyclass(eq)]
10#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
11pub enum CommonCrons {
12 Every1Minute,
13 Every5Minutes,
14 Every15Minutes,
15 Every30Minutes,
16 EveryHour,
17 Every6Hours,
18 Every12Hours,
19 EveryDay,
20 EveryWeek,
21}
22
23#[pymethods]
24impl CommonCrons {
25 #[getter]
26 pub fn cron(&self) -> String {
27 match self {
28 CommonCrons::Every1Minute => "0 * * * * * *".to_string(),
29 CommonCrons::Every5Minutes => {
30 "0 0,5,10,15,20,25,30,35,40,45,50,55 * * * * *".to_string()
31 }
32 CommonCrons::Every15Minutes => "0 0,15,30,45 * * * * *".to_string(),
33 CommonCrons::Every30Minutes => "0 0,30 * * * * *".to_string(),
34 CommonCrons::EveryHour => "0 0 * * * *".to_string(),
35 CommonCrons::Every6Hours => "0 0 */6 * * *".to_string(),
36 CommonCrons::Every12Hours => "0 0 */12 * * *".to_string(),
37 CommonCrons::EveryDay => "0 0 0 * * *".to_string(),
38 CommonCrons::EveryWeek => "0 0 0 * * SUN".to_string(),
39 }
40 }
41
42 pub fn get_next(&self) -> String {
43 match self {
44 CommonCrons::Every1Minute => {
45 let schedule = Schedule::from_str("0 * * * * * *").unwrap();
46 schedule.upcoming(Utc).next().unwrap().to_string()
47 }
48 CommonCrons::Every5Minutes => {
49 let schedule =
50 Schedule::from_str("0 0,5,10,15,20,25,30,35,40,45,50,55 * * * * *").unwrap();
51 schedule.upcoming(Utc).next().unwrap().to_string()
52 }
53 CommonCrons::Every15Minutes => {
54 let schedule = Schedule::from_str("0 0,15,30,45 * * * * *").unwrap();
55 schedule.upcoming(Utc).next().unwrap().to_string()
56 }
57 CommonCrons::Every30Minutes => {
58 let schedule = Schedule::from_str("0 0,30 * * * * *").unwrap();
59 schedule.upcoming(Utc).next().unwrap().to_string()
60 }
61 CommonCrons::EveryHour => {
62 let schedule = Schedule::from_str("0 0 * * * *").unwrap();
63 schedule.upcoming(Utc).next().unwrap().to_string()
64 }
65 CommonCrons::Every6Hours => {
66 let schedule = Schedule::from_str("0 0 */6 * * *").unwrap();
67 schedule.upcoming(Utc).next().unwrap().to_string()
68 }
69 CommonCrons::Every12Hours => {
70 let schedule = Schedule::from_str("0 0 */12 * * *").unwrap();
71 schedule.upcoming(Utc).next().unwrap().to_string()
72 }
73 CommonCrons::EveryDay => {
74 let schedule = Schedule::from_str("0 0 0 * * *").unwrap();
75 schedule.upcoming(Utc).next().unwrap().to_string()
76 }
77 CommonCrons::EveryWeek => {
78 let schedule = Schedule::from_str("0 0 0 * * SUN").unwrap();
79 schedule.upcoming(Utc).next().unwrap().to_string()
80 }
81 }
82 }
83}
84
85#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
86pub struct CustomInterval {
87 pub begin: DateTime<Utc>,
88 pub end: DateTime<Utc>,
89}
90
91impl CustomInterval {
92 pub fn new(begin: DateTime<Utc>, end: DateTime<Utc>) -> Result<Self, TypeError> {
93 if begin >= end {
94 return Err(TypeError::StartTimeError);
95 }
96 Ok(CustomInterval { begin, end })
97 }
98}
99
100#[pyclass(eq)]
101#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)]
102pub enum TimeInterval {
103 FifteenMinutes,
104 ThirtyMinutes,
105 OneHour,
106 #[default]
107 FourHours,
108 SixHours,
109 TwelveHours,
110 TwentyFourHours,
111 SevenDays,
112 Custom,
113}
114
115impl TimeInterval {
116 pub fn to_minutes(&self) -> i32 {
117 match self {
118 TimeInterval::FifteenMinutes => 15,
119 TimeInterval::ThirtyMinutes => 30,
120 TimeInterval::OneHour => 60,
121 TimeInterval::FourHours => 240,
122 TimeInterval::SixHours => 360,
123 TimeInterval::TwelveHours => 720,
124 TimeInterval::TwentyFourHours => 1440,
125 TimeInterval::SevenDays => 10080,
126 TimeInterval::Custom => 0,
127 }
128 }
129
130 pub fn to_begin_end_times(&self) -> Result<(DateTime<Utc>, DateTime<Utc>), TypeError> {
132 let end = Utc::now();
133 let start = match self {
134 TimeInterval::FifteenMinutes => end - chrono::Duration::minutes(15),
135 TimeInterval::ThirtyMinutes => end - chrono::Duration::minutes(30),
136 TimeInterval::OneHour => end - chrono::Duration::hours(1),
137 TimeInterval::FourHours => end - chrono::Duration::hours(4),
138 TimeInterval::SixHours => end - chrono::Duration::hours(6),
139 TimeInterval::TwelveHours => end - chrono::Duration::hours(12),
140 TimeInterval::TwentyFourHours => end - chrono::Duration::hours(24),
141 TimeInterval::SevenDays => end - chrono::Duration::days(7),
142 _ => {
143 return Err(TypeError::InvalidTimeIntervalError);
144 }
145 };
146 Ok((start, end))
147 }
148
149 pub fn from_string(time_interval: &str) -> TimeInterval {
150 match time_interval {
151 "15minute" => TimeInterval::FifteenMinutes,
152 "30minute" => TimeInterval::ThirtyMinutes,
153 "1hour" => TimeInterval::OneHour,
154 "4hour" => TimeInterval::FourHours,
155 "6hour" => TimeInterval::SixHours,
156 "12hour" => TimeInterval::TwelveHours,
157 "24hour" => TimeInterval::TwentyFourHours,
158 "7day" => TimeInterval::SevenDays,
159 "custom" => TimeInterval::Custom,
160 _ => TimeInterval::SixHours,
161 }
162 }
163}
164
165impl fmt::Display for TimeInterval {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 match self {
168 TimeInterval::FifteenMinutes => write!(f, "15minute"),
169 TimeInterval::ThirtyMinutes => write!(f, "30minute"),
170 TimeInterval::OneHour => write!(f, "1hour"),
171 TimeInterval::FourHours => write!(f, "4hour"),
172 TimeInterval::SixHours => write!(f, "6hour"),
173 TimeInterval::TwelveHours => write!(f, "12hour"),
174 TimeInterval::TwentyFourHours => write!(f, "24hour"),
175 TimeInterval::SevenDays => write!(f, "7day"),
176 TimeInterval::Custom => write!(f, "custom"),
177 }
178 }
179}
180
181#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
188 fn test_every_30_minutes_cron() {
189 let cron = CommonCrons::Every30Minutes;
190
191 assert_eq!(cron.cron(), "0 0,30 * * * * *");
193
194 let _next = cron.get_next();
196 }
197
198 #[test]
199 fn test_every_hour_cron() {
200 let cron = CommonCrons::EveryHour;
201 assert_eq!(cron.cron(), "0 0 * * * *");
203 let _next = cron.get_next();
204 }
205
206 #[test]
207 fn test_every_6_hours_cron() {
208 let cron = CommonCrons::Every6Hours;
209 assert_eq!(cron.cron(), "0 0 */6 * * *");
211 let _next = cron.get_next();
212 }
213
214 #[test]
215 fn test_every_12_hours_cron() {
216 let cron = CommonCrons::Every12Hours;
217 assert_eq!(cron.cron(), "0 0 */12 * * *");
219 let _next = cron.get_next();
220 }
221
222 #[test]
223 fn test_every_day_cron() {
224 let cron = CommonCrons::EveryDay;
225 assert_eq!(cron.cron(), "0 0 0 * * *");
227 let _next = cron.get_next();
228 }
229
230 #[test]
231 fn test_every_week_cron() {
232 let cron = CommonCrons::EveryWeek;
233 assert_eq!(cron.cron(), "0 0 0 * * SUN");
235 let _next = cron.get_next();
236 }
237
238 #[test]
239 fn test_cron_schedule_cron() {
240 let cron = CommonCrons::Every1Minute;
241 let schedule = Schedule::from_str(&cron.cron()).unwrap();
242 let next = schedule.upcoming(Utc).next().unwrap();
243 assert_eq!(next.to_string(), cron.get_next());
244
245 let cron = CommonCrons::Every5Minutes;
246 let schedule = Schedule::from_str(&cron.cron()).unwrap();
247 let next = schedule.upcoming(Utc).next().unwrap();
248 assert_eq!(next.to_string(), cron.get_next());
249
250 let cron = CommonCrons::Every15Minutes;
251 let schedule = Schedule::from_str(&cron.cron()).unwrap();
252 let next = schedule.upcoming(Utc).next().unwrap();
253 assert_eq!(next.to_string(), cron.get_next());
254
255 let cron = CommonCrons::Every30Minutes;
256 let schedule = Schedule::from_str(&cron.cron()).unwrap();
257 let next = schedule.upcoming(Utc).next().unwrap();
258 assert_eq!(next.to_string(), cron.get_next());
259
260 let cron = CommonCrons::EveryHour;
261 let schedule = Schedule::from_str(&cron.cron()).unwrap();
262 let next = schedule.upcoming(Utc).next().unwrap();
263 assert_eq!(next.to_string(), cron.get_next());
264
265 let cron = CommonCrons::Every6Hours;
266 let schedule = Schedule::from_str(&cron.cron()).unwrap();
267 let next = schedule.upcoming(Utc).next().unwrap();
268 assert_eq!(next.to_string(), cron.get_next());
269
270 let cron = CommonCrons::Every12Hours;
271 let schedule = Schedule::from_str(&cron.cron()).unwrap();
272 let next = schedule.upcoming(Utc).next().unwrap();
273 assert_eq!(next.to_string(), cron.get_next());
274
275 let cron = CommonCrons::EveryDay;
276 let schedule = Schedule::from_str(&cron.cron()).unwrap();
277 let next = schedule.upcoming(Utc).next().unwrap();
278 assert_eq!(next.to_string(), cron.get_next());
279
280 let cron = CommonCrons::EveryWeek;
281 let schedule = Schedule::from_str(&cron.cron()).unwrap();
282 let next = schedule.upcoming(Utc).next().unwrap();
283 assert_eq!(next.to_string(), cron.get_next());
284 }
285}