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}