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) { 29 } else { 28 }
18 } else if [1, 3, 5, 7, 8, 10, 12].contains(&month) {
19 31
20 } else {
21 30
22 }
23 }
24}
25
26impl std::str::FromStr for Period {
27 type Err = crate::Error;
28
29 fn from_str(s: &str) -> Result<Self, Self::Err> {
30 use Period::*;
31
32 match s {
33 "d" => Ok(Day),
34 "w" => Ok(Week),
35 "m" => Ok(Month),
36 "y" => Ok(Year),
37 _ => Err(crate::Error::InvalidPeriod(s.to_string())),
38 }
39 }
40}
41
42impl std::fmt::Display for Period {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 use Period::*;
45
46 let s = match *self {
47 Day => "d",
48 Week => "w",
49 Month => "m",
50 Year => "y",
51 };
52
53 f.write_str(s)?;
54
55 Ok(())
56 }
57}
58
59impl std::ops::Add<chrono::NaiveDate> for Period {
60 type Output = chrono::NaiveDate;
61
62 fn add(self, rhs: Self::Output) -> Self::Output {
63 let rec = super::Recurrence {
64 num: 1,
65 period: self,
66 strict: true,
67 };
68 rec + rhs
69 }
70}