1use time::Date;
2
3pub struct WeekdayIterator {
4 start: time::Date,
5 off: i8, // offset in weeks
6}
7
8impl Iterator for WeekdayIterator {
9 type Item = time::Date;
10
11 fn next(&mut self) -> Option<Self::Item> {
12 if self.off == 0 {
13 self.off += 1;
14 return Some(self.start);
15 }
16
17 let dur = time::Duration::weeks(self.off as i64);
18 let day = self.start.checked_add(dur)?;
19 if day.month() != self.start.month() {
20 None
21 } else {
22 self.off += 1;
23 Some(day)
24 }
25 }
26}
27
28fn iterator(year: i32, month: time::Month, wday: time::Weekday) -> Option<WeekdayIterator> {
29 let mut day = Date::from_calendar_date(year, month, 1).ok()?;
30
31 // Find first matching weekday in given month.
32 while day.weekday() != wday {
33 if day.month() != month {
34 return None;
35 }
36
37 day = day.next_day()?;
38 }
39
40 Some(WeekdayIterator { start: day, off: 0 })
41}
42
43pub fn filter(year: i32, month: time::Month, wday: time::Weekday) -> Option<Vec<time::Date>> {
44 iterator(year, month, wday).map(|it| it.collect())
45}
46
47////////////////////////////////////////////////////////////////////////
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use time::macros::date;
53
54 #[test]
55 fn filter_five() {
56 let mondays = filter(2023, time::Month::January, time::Weekday::Monday).unwrap();
57 assert_eq!(
58 mondays,
59 vec![
60 date!(2023 - 01 - 02),
61 date!(2023 - 01 - 09),
62 date!(2023 - 01 - 16),
63 date!(2023 - 01 - 23),
64 date!(2023 - 01 - 30),
65 ]
66 );
67 }
68
69 #[test]
70 fn filter_four() {
71 let mondays = filter(2023, time::Month::February, time::Weekday::Monday).unwrap();
72 assert_eq!(
73 mondays,
74 vec![
75 date!(2023 - 02 - 06),
76 date!(2023 - 02 - 13),
77 date!(2023 - 02 - 20),
78 date!(2023 - 02 - 27),
79 ]
80 );
81 }
82}