timer_util/
conf.rs

1use crate::compute::Composition;
2use crate::data::{Hour, Minuter, MonthDay, Second, WeekDay};
3use crate::traits::{FromData, ConfigOperator};
4use anyhow::{bail, Result};
5use chrono::{Datelike, Duration, Local, NaiveDateTime, Timelike};
6use log::debug;
7use std::fmt::{Debug, Formatter};
8use std::ops::{Add, Bound, RangeBounds, Sub};
9
10/// 定时器配置
11#[derive(Debug, Clone)]
12pub struct TimerConf {
13    pub(crate) days: Days,
14    pub(crate) hours: Hours,
15    pub(crate) minuters: Minuters,
16    pub(crate) seconds: Seconds,
17}
18
19impl TimerConf {
20
21    /// 在给定的日期时间范围内,返回符合定时器的所有时间点
22    pub fn datetimes(&self, range: impl RangeBounds<NaiveDateTime>) -> Result<Vec<NaiveDateTime>> {
23        // 转成 a..=b
24        let mut start = match range.start_bound() {
25            Bound::Unbounded => bail!("不支持该模式"),
26            Bound::Included(first) => first.sub(Duration::seconds(1)),
27            Bound::Excluded(first) => first.clone(),
28        };
29        let end = match range.end_bound() {
30            Bound::Unbounded => bail!("不支持该模式"),
31            Bound::Included(end) => end.clone(),
32            Bound::Excluded(end) => end.sub(Duration::seconds(1)),
33        };
34        if start >= end {
35            bail!("起始-结束日期配置错误")
36        }
37        let mut date_times = Vec::new();
38        while start <= end {
39            let next = self.next_with_time(start);
40            if next <= end {
41                date_times.push(next);
42                start = next;
43            } else {
44                break;
45            }
46        }
47        Ok(date_times)
48    }
49    /// 以给定的时间点为起点(不包含该时点),返回下个符合定时器的时间点
50    pub fn next_with_time(&self, now: NaiveDateTime) -> NaiveDateTime {
51        let now = now.add(Duration::seconds(1));
52        let mut composition = Composition::from(
53            now,
54            self.days.clone(),
55            self.hours.clone(),
56            self.minuters.clone(),
57            self.seconds.clone(),
58        );
59        debug!("Composition: {:?}", composition);
60        let next = composition.next();
61        next
62    }
63    /// 以当前时间点为起点,返回距离下个符合时间点的时间间隔(s)
64    pub fn next(&self) -> u64 {
65        let now_local = Local::now().naive_local();
66        let next_local = self.next_with_time(now_local);
67        let times = (next_local.timestamp() - now_local.timestamp()) as u64;
68        debug!(
69            "now : {}-{:02}-{:02} {:02}:{:02}:{:02}",
70            now_local.year(),
71            now_local.month(),
72            now_local.day(),
73            now_local.hour(),
74            now_local.minute(),
75            now_local.second()
76        );
77        debug!(
78            "next: {}-{:02}-{:02} {:02}:{:02}:{:02}",
79            next_local.year(),
80            next_local.month(),
81            next_local.day(),
82            next_local.hour(),
83            next_local.minute(),
84            next_local.second()
85        );
86        times
87    }
88}
89#[derive(Debug, Clone)]
90pub enum Days {
91    MonthDays(MonthDays),
92    WeekDays(WeekDays),
93    MonthAndWeekDays(MonthDays, WeekDays)
94}
95
96impl Days {
97    pub(crate) fn month_days(&self, week_day: WeekDay) -> MonthDays {
98        match self {
99            Days::MonthDays(month_days) => { month_days.clone()}
100            Days::WeekDays(week_days) => {week_days.to_month_days(week_day)}
101            Days::MonthAndWeekDays(month_days, week_days) => {
102                month_days.merge(&week_days.to_month_days(week_day))
103            }
104        }
105    }
106    pub(crate) fn update_month_days(self, month_days: MonthDays) -> Self {
107        match self {
108            Days::MonthDays(_) => {Self::MonthDays(month_days)}
109            Days::WeekDays(week_days) => {Self::MonthAndWeekDays(month_days, week_days)}
110            Days::MonthAndWeekDays(_, week_days) => {Self::MonthAndWeekDays(month_days, week_days)}
111        }
112    }
113    pub(crate) fn update_week_days(self, week_days: WeekDays) -> Self {
114        match self {
115            Days::MonthDays(month_days) => {Self::MonthAndWeekDays(month_days, week_days)}
116            Days::WeekDays(_) => {Self::WeekDays(week_days)}
117            Days::MonthAndWeekDays(month_days, _) => {Self::MonthAndWeekDays(month_days, week_days)}
118        }
119    }
120    // pub(crate) fn is_zero(&self) -> bool {
121    //     match self {
122    //         Days::MonthDays(month_days) => month_days.is_zero(),
123    //         Days::WeekDays(week_days) => week_days.is_zero(),
124    //         Days::MonthAndWeekDays(month_days, week_days) => month_days.is_zero() || week_days.is_zero()
125    //     }
126    // }
127}
128
129
130/// 每月的天数配置。如配置(选中)1号、3号……29号
131#[derive(Clone)]
132pub struct MonthDays(u64);
133/// 每星期的天数配置。如配置(选中)周一……周六
134#[derive(Clone)]
135pub struct WeekDays(u64);
136/// 每天的小时(时钟)配置。如配置(选中)0点、3点、9点、……18点
137#[derive(Clone)]
138pub struct Hours(u64);
139/// 每小时的分钟配置。如配置(选中)0分、5分……58分
140#[derive(Clone, Eq, PartialEq)]
141pub struct Minuters(u64);
142/// 每分钟的秒钟配置。如配置(选中)0秒、5秒……58秒
143#[derive(Clone)]
144pub struct Seconds(u64);
145impl ConfigOperator for Hours {
146    const MIN: u64 = 0;
147    const MAX: u64 = 23;
148    const DEFAULT_MAX: u64 = (u32::MAX >> 8) as u64;
149    type DataTy = Hour;
150
151    fn min_val(&self) -> Self::DataTy {
152        Self::DataTy::from_data(self._min_val())
153    }
154    fn _default() -> Self {
155        Self(0)
156    }
157    fn _val(&self) -> u64 {
158        self.0
159    }
160    fn next(&self, index: Self::DataTy) -> Option<Self::DataTy> {
161        self._next(index)
162            .and_then(|x| Some(Self::DataTy::from_data(x)))
163    }
164    fn _val_mut(&mut self, val: u64) {
165        self.0 = val
166    }
167
168}
169impl ConfigOperator for Seconds {
170    const MIN: u64 = 0;
171    const MAX: u64 = 59;
172    const DEFAULT_MAX: u64 = u64::MAX >> 4;
173    type DataTy = Second;
174    fn min_val(&self) -> Self::DataTy {
175        Self::DataTy::from_data(self._min_val())
176    }
177    fn next(&self, index: Self::DataTy) -> Option<Self::DataTy> {
178        self._next(index)
179            .and_then(|x| Some(Self::DataTy::from_data(x)))
180    }
181    fn _default() -> Self {
182        Self(0)
183    }
184    fn _val(&self) -> u64 {
185        self.0
186    }
187    fn _val_mut(&mut self, val: u64) {
188        self.0 = val
189    }
190}
191impl ConfigOperator for Minuters {
192    const MIN: u64 = 0;
193    const MAX: u64 = 59;
194    const DEFAULT_MAX: u64 = u64::MAX >> 4;
195    type DataTy = Minuter;
196    fn min_val(&self) -> Self::DataTy {
197        Self::DataTy::from_data(self._min_val())
198    }
199    fn next(&self, index: Self::DataTy) -> Option<Self::DataTy> {
200        self._next(index)
201            .and_then(|x| Some(Self::DataTy::from_data(x)))
202    }
203    fn _default() -> Self {
204        Self(0)
205    }
206    fn _val(&self) -> u64 {
207        self.0
208    }
209    fn _val_mut(&mut self, val: u64) {
210        self.0 = val
211    }
212}
213
214impl ConfigOperator for MonthDays {
215    const MIN: u64 = 1;
216    const MAX: u64 = 31;
217    const DEFAULT_MAX: u64 = (u32::MAX << 1) as u64;
218    type DataTy = MonthDay;
219    fn next(&self, index: Self::DataTy) -> Option<Self::DataTy> {
220        self._next(index)
221            .and_then(|x| Some(Self::DataTy::from_data(x)))
222    }
223    fn _default() -> Self {
224        Self(0)
225    }
226    fn min_val(&self) -> Self::DataTy {
227        Self::DataTy::from_data(self._min_val())
228    }
229    fn _val(&self) -> u64 {
230        self.0
231    }
232    fn _val_mut(&mut self, val: u64) {
233        self.0 = val
234    }
235}
236
237impl Minuters {
238    pub fn every(interval: u64) -> Self {
239        if interval == 0 {
240            Self::_default()
241        } else {
242            let mut val = 0u64;
243            let mut minuters = Self::_default();
244            while val <= Self::MAX {
245                minuters = minuters.add(Minuter::from_data(val));
246                val += interval
247            }
248            minuters
249        }
250    }
251}
252
253impl ConfigOperator for WeekDays {
254    const DEFAULT_MAX: u64 = (u8::MAX << 1) as u64;
255    const MIN: u64 = 1;
256    const MAX: u64 = 7;
257
258    type DataTy = WeekDay;
259
260    fn _default() -> Self {
261        Self(0)
262    }
263
264    fn min_val(&self) -> Self::DataTy {
265        Self::DataTy::from_data(self._min_val())
266    }
267    fn next(&self, index: Self::DataTy) -> Option<Self::DataTy> {
268        self._next(index)
269            .and_then(|x| Some(Self::DataTy::from_data(x)))
270    }
271
272    fn _val(&self) -> u64 {
273        self.0
274    }
275
276    fn _val_mut(&mut self, val: u64) {
277        self.0 = val;
278    }
279}
280
281/// 为啥不是实现Operator
282#[allow(dead_code)]
283impl WeekDays {
284    pub(crate) fn to_month_days(&self, start: WeekDay) -> MonthDays {
285        // 因WeekDays起始位置为1,右移去掉冗余的0位
286        let week_unit = self.0 >> 1;
287        // 按7天,拼出足够长的天数(保证下一步截断后,总天数>= 31)
288        // 按起始星期几截断
289        // 因MonthDays起始位置为1,再左移1位
290        let days = (week_unit | week_unit << 7 | week_unit << 14 | week_unit << 21 | week_unit << 28 | week_unit << 35) >> (start as u64 - 1) << 1;
291
292        let mut month_days = MonthDays::_default();
293        month_days._val_mut(days);
294        month_days
295        //
296        //
297        // let mut next = Some(WeekArray::init(start));
298        // let conf_week_days = self.to_vec();
299        //
300        // let mut monthdays = MonthDays::_default();
301        // while let Some(ref weekday) = next {
302        //     for x in &conf_week_days {
303        //         if let Some(day) = weekday.day(*x as usize) {
304        //             monthdays = monthdays.add(MonthDay::from_data(day));
305        //         }
306        //     }
307        //     next = weekday.next();
308        // }
309        // monthdays
310    }
311}
312//
313// #[derive(Debug)]
314// pub struct NextTime {
315//     hours: u64,
316//     minuters: u64,
317//     seconds: u64,
318// }
319// impl NextTime {
320//     fn init(mut times: u64) -> Self {
321//         let seconds = times % 60;
322//         times = times / 60;
323//         let minuters = times % 60;
324//         times = times / 60;
325//         let hours = times % 60;
326//         Self {
327//             seconds,
328//             minuters,
329//             hours,
330//         }
331//     }
332// }
333
334impl Debug for Seconds {
335    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
336        if self.0 == u64::MAX >> 4 {
337            write!(f, "all seconds.")
338        } else {
339            write!(f, "seconds: {:?}.", self.to_vec())
340        }
341    }
342}
343impl Debug for Minuters {
344    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
345        if self.0 == u64::MAX >> 4 {
346            write!(f, "all minuters.")
347        } else {
348            write!(f, "minuters: {:?}.", self.to_vec())
349        }
350    }
351}
352impl Debug for Hours {
353    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
354        if self.0 == (u32::MAX >> 8) as u64 {
355            write!(f, "all hours.")
356        } else {
357            write!(f, "hours: {:?}.", self.to_vec())
358        }
359    }
360}
361impl Debug for MonthDays {
362    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
363        if self.0 == (u32::MAX << 1) as u64 {
364            write!(f, "all month days.")
365        } else {
366            write!(f, "month days: {:?}.", self.to_vec())
367        }
368    }
369}
370impl Debug for WeekDays {
371    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
372        if self.0 == (u8::MAX << 1) as u64 {
373            write!(f, "all week days.")
374        } else {
375            write!(f, "week day's array index: {:?}.", self.to_vec())
376        }
377    }
378}
379
380#[cfg(test)]
381mod test {
382    use super::{Hours, Minuters, MonthDays, ConfigOperator, Seconds, WeekDays};
383    use crate::conf::TimerConf;
384    #[allow(unused_imports)]
385    use crate::data::{DateTime, Hour::*, Minuter::*, MonthDay::*, Second::*, WeekDay::*};
386    use crate::*;
387    use anyhow::Result;
388    use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime};
389    use log::debug;
390    use std::ops::Sub;
391
392
393    pub(crate) fn datetime(
394        year: i32,
395        month: u32,
396        day: u32,
397        hour: u32,
398        min: u32,
399        second: u32,
400    ) -> NaiveDateTime {
401        NaiveDateTime::new(
402            NaiveDate::from_ymd(year, month, day),
403            NaiveTime::from_hms(hour, min, second),
404        )
405    }
406
407    #[test]
408    fn test_auto() -> anyhow::Result<()> {
409        // custom_utils::logger::logger_stdout_debug();
410        let conf = configure_weekday(WeekDays::default_array(&[W1, W3, W5]))
411            .conf_month_days(
412                MonthDays::default_range(D5..D10)?
413                    .add_range(D15..D20)?
414                    .add_range(D25..D30)?,
415            )
416            .build_with_hours(Hours::default_array(&[H5, H10, H15, H20]))
417            .build_with_minuter(Minuters::default_array(&[M15, M30, M45]))
418            .build_with_second(Seconds::default_value(S0));
419
420        let mut start = datetime(2022, 7, 4, 20, 15, 0);
421        let end = datetime(2033, 8, 15, 12, 30, 45);
422
423        // let datetimes = conf.datetimes(start.clone()..end)?;
424        let datetimes = conf.datetimes(start.clone()..end)?;
425        start = start.sub(Duration::seconds(1));
426        let mut next = end;
427        for datetime in datetimes {
428            next = conf.next_with_time(start.clone());
429            assert_eq!(datetime, next, "{:?} - {:?}", start, next);
430            start = datetime;
431        }
432        assert_eq!(
433            datetime(2033, 8, 15, 10, 45, 0),
434            next,
435            "{:?} - {:?}",
436            end,
437            next
438        );
439
440        let mut start = datetime(2022, 7, 4, 20, 15, 0);
441        let end = datetime(2033, 8, 15, 15, 30, 0);
442        // let datetimes = conf.datetimes(start.clone()..end.clone())?;
443        let datetimes = conf.datetimes(start.clone()..end.clone())?;
444        start = start.sub(Duration::seconds(1));
445        let mut next = start.clone();
446        for datetime in datetimes {
447            next = conf.next_with_time(start.clone());
448            assert_eq!(datetime, next, "{:?} - {:?}", start, next);
449            start = datetime;
450        }
451        assert_eq!(
452            datetime(2033, 8, 15, 15, 15, 0),
453            next,
454            "{:?} - {:?}",
455            end,
456            next
457        );
458        Ok(())
459    }
460    #[test]
461    fn test_auto_pre() -> anyhow::Result<()> {
462        // custom_utils::logger::logger_stdout_debug();
463        let conf = configure_weekday(WeekDays::default_array(&[W1, W3, W5]))
464            .conf_month_days(
465                MonthDays::default_range(D5..D10)?
466                    .add_range(D15..D20)?
467                    .add_range(D25..D30)?,
468            )
469            .build_with_hours(Hours::default_array(&[H5, H10, H15, H20]))
470            .build_with_minuter(Minuters::default_array(&[M15, M30, M45]))
471            .build_with_second(Seconds::default_value(S0));
472
473        let start = datetime(2022, 7, 4, 22, 17, 10);
474        let end = datetime(2022, 7, 5, 12, 30, 45);
475
476        // let datetimes = conf.datetimes(start.clone()..end)?;
477        let datetimes = conf.datetimes(start.clone()..end)?;
478        debug!("{:?}", datetimes);
479        Ok(())
480    }
481
482    /// 测试WeekDays生成当月的月日期
483    #[test]
484    fn test_to_month_days() {
485        let month_days0 = WeekDays::default_array(&[W1, W3, W5, W7]).to_month_days(W3);
486        assert_eq!(
487            month_days0.to_vec(),
488            vec![1, 3, 5, 6, 8, 10, 12, 13, 15, 17, 19, 20, 22, 24, 26, 27, 29, 31]
489        );
490
491        let month_days1 = WeekDays::default_array(&[W1, W3, W5]).to_month_days(W1);
492        assert_eq!(
493            month_days1.to_vec(),
494            vec![1, 3, 5, 8, 10, 12, 15, 17, 19, 22, 24, 26, 29, 31]
495        );
496        let month_days2 = month_days0.merge(&month_days1);
497        assert_eq!(
498            month_days2.to_vec(),
499            vec![1, 3, 5, 6, 8, 10, 12, 13, 15, 17, 19, 20, 22, 24, 26, 27, 29, 31]
500        );
501        // debug!("{:?}", month_days.to_vec());
502    }
503    #[test]
504    fn test_datetimes() -> Result<()> {
505        // custom_utils::logger::logger_stdout_debug();
506        let some_datetimes = [
507            datetime(2020, 5, 15, 10, 30, 30),
508            datetime(2020, 5, 15, 10, 30, 45),
509            datetime(2020, 5, 15, 10, 45, 15),
510            datetime(2020, 5, 15, 10, 45, 30),
511            datetime(2020, 5, 15, 10, 45, 45),
512            datetime(2020, 5, 15, 15, 15, 15),
513            datetime(2020, 5, 15, 15, 15, 30),
514            datetime(2020, 5, 15, 15, 15, 45),
515            datetime(2020, 5, 15, 15, 30, 15),
516            datetime(2020, 5, 15, 15, 30, 30),
517        ];
518        let conf = configure_weekday(WeekDays::default_array(&[W5, W3]))
519            .conf_month_days(MonthDays::default_array(&[D5, D15, D24]))
520            .build_with_hours(Hours::default_array(&[H5, H10, H15]))
521            .build_with_minuter(Minuters::default_array(&[M15, M30, M45]))
522            .build_with_second(Seconds::default_array(&[S15, S30, S45]));
523        debug!("2020-5-15 10:30:17");
524        // let datetimes =
525        //     conf.datetimes(datetime(2020, 5, 15, 10, 30, 17)..=datetime(2020, 5, 15, 15, 30, 30))?;
526        let datetimes =
527            conf.datetimes(datetime(2020, 5, 15, 10, 30, 17)..=datetime(2020, 5, 15, 15, 30, 30))?;
528
529        assert_eq!(datetimes.as_slice(), &some_datetimes[..]);
530
531        Ok(())
532    }
533
534    #[test]
535    fn test() -> Result<()> {
536        // custom_utils::logger::logger_stdout_debug();
537        let conf = configure_weekday(WeekDays::default_array(&[W5, W3]))
538            .conf_month_days(MonthDays::default_array(&[D5, D15, D24]))
539            .build_with_hours(Hours::default_array(&[H5, H10, H15]))
540            .build_with_minuter(Minuters::default_array(&[M15, M30, M45]))
541            .build_with_second(Seconds::default_array(&[S15, S30, S45]));
542
543        compare(
544            &conf,
545            &[
546                datetime(2020, 5, 15, 10, 30, 30),
547                datetime(2020, 5, 15, 10, 30, 45),
548                datetime(2020, 5, 15, 10, 45, 15),
549                datetime(2020, 5, 15, 10, 45, 30),
550                datetime(2020, 5, 15, 10, 45, 45),
551                datetime(2020, 5, 15, 15, 15, 15),
552                datetime(2020, 5, 15, 15, 15, 30),
553                datetime(2020, 5, 15, 15, 15, 45),
554                datetime(2020, 5, 15, 15, 30, 15),
555                datetime(2020, 5, 15, 15, 30, 30),
556            ],
557        );
558        // -------------------------------
559        let dt0 = DateTime {
560            date: NaiveDate::from_ymd_opt(2022, 5, 20).unwrap(),
561            month_day: D20,
562            week_day: W5,
563            hour: H15,
564            minuter: M45,
565            second: S45,
566        };
567        {
568            let dist: DateTime = conf.next_with_time(dt0.into()).into();
569            let mut dt0_dist = dt0.clone();
570            dt0_dist.week_day = W2;
571            dt0_dist.month_day = D24;
572            dt0_dist.second = S15;
573            dt0_dist.minuter = M15;
574            dt0_dist.hour = H5;
575            dt0_dist.date = NaiveDate::from_ymd_opt(2022, 5, 24).unwrap();
576            assert_eq!(dist, dt0_dist);
577        }
578        // -------------------------------
579        let conf = configure_weekday(WeekDays::default_array(&[W5, W3]))
580            .conf_month_days(MonthDays::default_array(&[D5, D15, D31]))
581            .build_with_hours(Hours::default_array(&[H5, H10, H15]))
582            .build_with_minuter(Minuters::default_array(&[M15, M30, M45]))
583            .build_with_second(Seconds::default_array(&[S15, S30, S45]));
584        debug!("{:?}", conf);
585        let dt0 = DateTime {
586            date: NaiveDate::from_ymd_opt(2022, 4, 29).unwrap(),
587            month_day: D29,
588            week_day: W5,
589            hour: H15,
590            minuter: M45,
591            second: S45,
592        };
593        {
594            let dist: DateTime = conf.next_with_time(dt0.into()).into();
595            let mut dt0_dist = dt0.clone();
596            dt0_dist.week_day = W3;
597            dt0_dist.month_day = D4;
598            dt0_dist.second = S15;
599            dt0_dist.minuter = M15;
600            dt0_dist.hour = H5;
601            dt0_dist.date = NaiveDate::from_ymd_opt(2022, 5, 4).unwrap();
602            assert_eq!(dist, dt0_dist);
603        }
604        Ok(())
605    }
606
607    #[test]
608    fn test_year() -> Result<()> {
609        // custom_utils::logger::logger_stdout_debug();
610        let conf = configure_monthday(MonthDays::default_value(D31))
611            .build_with_hours(Hours::default_array(&[H12]))
612            .build_with_minuter(Minuters::default_array(&[M30]))
613            .build_with_second(Seconds::default_array(&[S0]));
614        let dt0 = DateTime {
615            date: NaiveDate::from_ymd_opt(2021, 12, 31).unwrap(),
616            month_day: D31,
617            week_day: W5,
618            hour: H12,
619            minuter: M30,
620            second: S30,
621        };
622        {
623            let dist: DateTime = conf.next_with_time(dt0.into()).into();
624            let mut dt0_dist = dist.clone();
625            dt0_dist.second = S0;
626            dt0_dist.minuter = M30;
627            dt0_dist.hour = H12;
628            dt0_dist.week_day = W1;
629            dt0_dist.month_day = D31;
630            assert!(dist == dt0_dist, "{:?}", dist);
631            assert!(dist.date.year() == 2022, "{:?}", dist.date);
632            assert!(dist.date.month() == 1, "{:?}", dist.date);
633        }
634        Ok(())
635    }
636    #[test]
637    fn test_month() -> Result<()> {
638        // custom_utils::logger::logger_stdout_debug();
639        let conf = configure_monthday(MonthDays::default_value(D31))
640            .build_with_hours(Hours::default_array(&[H12]))
641            .build_with_minuter(Minuters::default_array(&[M30]))
642            .build_with_second(Seconds::default_array(&[S0]));
643        let dt0 = DateTime {
644            date: NaiveDate::from_ymd_opt(2022, 1, 31).unwrap(),
645            month_day: D31,
646            week_day: W5,
647            hour: H12,
648            minuter: M30,
649            second: S30,
650        };
651        {
652            let dist: DateTime = conf.next_with_time(dt0.into()).into();
653            let mut dt0_dist = dist.clone();
654            dt0_dist.second = S0;
655            dt0_dist.minuter = M30;
656            dt0_dist.hour = H12;
657            dt0_dist.week_day = W4;
658            dt0_dist.month_day = D31;
659            assert!(dist == dt0_dist, "{:?}", dist);
660            assert!(dist.date.year() == 2022, "{:?}", dist.date);
661            assert!(dist.date.month() == 3, "{:?}", dist.date);
662        }
663        Ok(())
664    }
665
666    fn compare(conf: &TimerConf, times: &[NaiveDateTime]) {
667        let len = times.len() - 1;
668        let mut index = 0;
669        loop {
670            assert_eq!(
671                conf.next_with_time(times[index].clone()),
672                times[index + 1].clone()
673            );
674            index += 1;
675            if index == len {
676                break;
677            }
678        }
679    }
680    #[test]
681    fn test_every() {
682        use Minuter::*;
683        let minuters = Minuters::every(11);
684        assert_eq!(minuters, Minuters::default_array(&[M0, M11, M22, M33, M44, M55]));
685        let minuters = Minuters::every(0);
686        assert_eq!(minuters, Minuters::_default());
687        let minuters = Minuters::every(30);
688        assert_eq!(minuters, Minuters::default_array(&[M0, M30]));
689        let minuters = Minuters::every(31);
690        assert_eq!(minuters, Minuters::default_array(&[M0, M31]));
691        let minuters = Minuters::every(60);
692        assert_eq!(minuters, Minuters::default_array(&[M0]));
693
694        let minuters = Minuters::every(500);
695        assert_eq!(minuters, Minuters::default_array(&[M0]));
696    }
697}