todo_txt/task/
period.rs

1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3pub enum Period {
4    Day,
5    Week,
6    Month,
7    Year,
8}
9
10impl Period {
11    fn is_leap_year(year: i32) -> bool {
12        year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
13    }
14
15    pub fn days_in_month(month: u32, year: i32) -> u32 {
16        if month == 2 {
17            if Self::is_leap_year(year) {
18                29
19            } else {
20                28
21            }
22        } else if [1, 3, 5, 7, 8, 10, 12].contains(&month) {
23            31
24        } else {
25            30
26        }
27    }
28}
29
30impl std::str::FromStr for Period {
31    type Err = crate::Error;
32
33    fn from_str(s: &str) -> Result<Self, Self::Err> {
34        use Period::*;
35
36        match s {
37            "d" => Ok(Day),
38            "w" => Ok(Week),
39            "m" => Ok(Month),
40            "y" => Ok(Year),
41            _ => Err(crate::Error::InvalidPeriod(s.to_string())),
42        }
43    }
44}
45
46impl std::fmt::Display for Period {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        use Period::*;
49
50        let s = match *self {
51            Day => "d",
52            Week => "w",
53            Month => "m",
54            Year => "y",
55        };
56
57        f.write_str(s)?;
58
59        Ok(())
60    }
61}
62
63impl std::ops::Add<chrono::NaiveDate> for Period {
64    type Output = chrono::NaiveDate;
65
66    fn add(self, rhs: Self::Output) -> Self::Output {
67        let rec = super::Recurrence {
68            num: 1,
69            period: self,
70            strict: true,
71        };
72        rec + rhs
73    }
74}