chronos_parser_rs/
cron_schedule.rs1use std::marker::PhantomData;
2
3use anyhow::{anyhow, Result};
4use chrono::{DateTime, TimeZone};
5use intervals_rs::LimitValue;
6
7use crate::{CronInterval, CronIntervalIterator, CronParser, CronSpecification, Expr};
8
9#[derive(Debug, Clone)]
12pub struct CronSchedule<Tz>
13where
14 Tz: TimeZone, {
15 expr: Expr,
16 phantom: PhantomData<Tz>,
17}
18
19impl<Tz: TimeZone> CronSchedule<Tz> {
20 pub fn new(crond_string: &str) -> Result<Self> {
36 let result = CronParser::parse(crond_string).to_result();
37 if result.is_err() {
38 return Err(anyhow!("Failed to parse crond string: {}", result.err().unwrap()));
39 }
40 Ok(Self {
41 expr: result.unwrap(),
42 phantom: PhantomData,
43 })
44 }
45
46 pub fn cron_interval(&self, start: DateTime<Tz>) -> CronInterval<Tz, CronSpecification> {
49 let spec = CronSpecification::new(self.expr.clone());
50 let start = LimitValue::Limit(start);
51 let end = LimitValue::Limitless;
52 CronInterval::new(start, end, spec)
53 }
54
55 pub fn upcoming(&self, start: DateTime<Tz>) -> CronIntervalIterator<Tz, CronSpecification> {
58 self.cron_interval(start.clone()).iter(start.timezone())
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use chrono::{TimeZone, Utc};
66
67 #[test]
68 fn test_iterator() {
69 let dt: chrono::DateTime<Utc> = Utc.with_ymd_and_hms(2021, 1, 1, 1, 1, 0).unwrap();
70
71 let itr = CronSchedule::new("0-59/30 0-23/2 * * *").unwrap().upcoming(dt);
72
73 let dt_vec = itr.take(5).collect::<Vec<_>>();
74 assert_eq!(dt_vec[0], Utc.with_ymd_and_hms(2021, 1, 1, 2, 0, 0).unwrap());
75 assert_eq!(dt_vec[1], Utc.with_ymd_and_hms(2021, 1, 1, 2, 30, 0).unwrap());
76 assert_eq!(dt_vec[2], Utc.with_ymd_and_hms(2021, 1, 1, 4, 0, 0).unwrap());
77 assert_eq!(dt_vec[3], Utc.with_ymd_and_hms(2021, 1, 1, 4, 30, 0).unwrap());
78 assert_eq!(dt_vec[4], Utc.with_ymd_and_hms(2021, 1, 1, 6, 0, 0).unwrap());
79 }
85}