ncalendar

Reimplementation of the BSD calendar(1) program in Rust

git clone https://git.8pit.net/ncalendar.git

 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}