time/
month.rs

1//! The `Month` enum and its associated `impl`s.
2
3use core::fmt;
4use core::num::NonZeroU8;
5use core::str::FromStr;
6
7use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
8
9use self::Month::*;
10use crate::{error, util};
11
12/// Months of the year.
13#[repr(u8)]
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum Month {
16    #[allow(missing_docs)]
17    January = 1,
18    #[allow(missing_docs)]
19    February = 2,
20    #[allow(missing_docs)]
21    March = 3,
22    #[allow(missing_docs)]
23    April = 4,
24    #[allow(missing_docs)]
25    May = 5,
26    #[allow(missing_docs)]
27    June = 6,
28    #[allow(missing_docs)]
29    July = 7,
30    #[allow(missing_docs)]
31    August = 8,
32    #[allow(missing_docs)]
33    September = 9,
34    #[allow(missing_docs)]
35    October = 10,
36    #[allow(missing_docs)]
37    November = 11,
38    #[allow(missing_docs)]
39    December = 12,
40}
41
42impl Month {
43    /// Create a `Month` from its numerical value.
44    pub(crate) const fn from_number(n: NonZeroU8) -> Result<Self, error::ComponentRange> {
45        match n.get() {
46            1 => Ok(January),
47            2 => Ok(February),
48            3 => Ok(March),
49            4 => Ok(April),
50            5 => Ok(May),
51            6 => Ok(June),
52            7 => Ok(July),
53            8 => Ok(August),
54            9 => Ok(September),
55            10 => Ok(October),
56            11 => Ok(November),
57            12 => Ok(December),
58            n => Err(error::ComponentRange {
59                name: "month",
60                minimum: 1,
61                maximum: 12,
62                value: n as _,
63                conditional_range: false,
64            }),
65        }
66    }
67
68    /// Get the number of days in the month of a given year.
69    ///
70    /// ```rust
71    /// # use time::Month;
72    /// assert_eq!(Month::February.length(2020), 29);
73    /// ```
74    pub const fn length(self, year: i32) -> u8 {
75        match self {
76            January | March | May | July | August | October | December => 31,
77            April | June | September | November => 30,
78            February if util::is_leap_year(year) => 29,
79            February => 28,
80        }
81    }
82
83    /// Get the previous month.
84    ///
85    /// ```rust
86    /// # use time::Month;
87    /// assert_eq!(Month::January.previous(), Month::December);
88    /// ```
89    pub const fn previous(self) -> Self {
90        match self {
91            January => December,
92            February => January,
93            March => February,
94            April => March,
95            May => April,
96            June => May,
97            July => June,
98            August => July,
99            September => August,
100            October => September,
101            November => October,
102            December => November,
103        }
104    }
105
106    /// Get the next month.
107    ///
108    /// ```rust
109    /// # use time::Month;
110    /// assert_eq!(Month::January.next(), Month::February);
111    /// ```
112    pub const fn next(self) -> Self {
113        match self {
114            January => February,
115            February => March,
116            March => April,
117            April => May,
118            May => June,
119            June => July,
120            July => August,
121            August => September,
122            September => October,
123            October => November,
124            November => December,
125            December => January,
126        }
127    }
128
129    /// Get n-th next month.
130    ///
131    /// ```rust
132    /// # use time::Month;
133    /// assert_eq!(Month::January.nth_next(4), Month::May);
134    /// assert_eq!(Month::July.nth_next(9), Month::April);
135    /// ```
136    pub const fn nth_next(self, n: u8) -> Self {
137        match (self as u8 - 1 + n % 12) % 12 {
138            0 => January,
139            1 => February,
140            2 => March,
141            3 => April,
142            4 => May,
143            5 => June,
144            6 => July,
145            7 => August,
146            8 => September,
147            9 => October,
148            10 => November,
149            val => {
150                debug_assert!(val == 11);
151                December
152            }
153        }
154    }
155
156    /// Get n-th previous month.
157    ///
158    /// ```rust
159    /// # use time::Month;
160    /// assert_eq!(Month::January.nth_prev(4), Month::September);
161    /// assert_eq!(Month::July.nth_prev(9), Month::October);
162    /// ```
163    pub const fn nth_prev(self, n: u8) -> Self {
164        match self as i8 - 1 - (n % 12) as i8 {
165            1 | -11 => February,
166            2 | -10 => March,
167            3 | -9 => April,
168            4 | -8 => May,
169            5 | -7 => June,
170            6 | -6 => July,
171            7 | -5 => August,
172            8 | -4 => September,
173            9 | -3 => October,
174            10 | -2 => November,
175            11 | -1 => December,
176            val => {
177                debug_assert!(val == 0);
178                January
179            }
180        }
181    }
182}
183
184mod private {
185    #[non_exhaustive]
186    #[derive(Debug, Clone, Copy)]
187    pub struct MonthMetadata;
188}
189use private::MonthMetadata;
190
191impl SmartDisplay for Month {
192    type Metadata = MonthMetadata;
193
194    fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
195        match self {
196            January => Metadata::new(7, self, MonthMetadata),
197            February => Metadata::new(8, self, MonthMetadata),
198            March => Metadata::new(5, self, MonthMetadata),
199            April => Metadata::new(5, self, MonthMetadata),
200            May => Metadata::new(3, self, MonthMetadata),
201            June => Metadata::new(4, self, MonthMetadata),
202            July => Metadata::new(4, self, MonthMetadata),
203            August => Metadata::new(6, self, MonthMetadata),
204            September => Metadata::new(9, self, MonthMetadata),
205            October => Metadata::new(7, self, MonthMetadata),
206            November => Metadata::new(8, self, MonthMetadata),
207            December => Metadata::new(8, self, MonthMetadata),
208        }
209    }
210
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        f.pad(match self {
213            January => "January",
214            February => "February",
215            March => "March",
216            April => "April",
217            May => "May",
218            June => "June",
219            July => "July",
220            August => "August",
221            September => "September",
222            October => "October",
223            November => "November",
224            December => "December",
225        })
226    }
227}
228
229impl fmt::Display for Month {
230    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231        SmartDisplay::fmt(self, f)
232    }
233}
234
235impl FromStr for Month {
236    type Err = error::InvalidVariant;
237
238    fn from_str(s: &str) -> Result<Self, Self::Err> {
239        match s {
240            "January" => Ok(January),
241            "February" => Ok(February),
242            "March" => Ok(March),
243            "April" => Ok(April),
244            "May" => Ok(May),
245            "June" => Ok(June),
246            "July" => Ok(July),
247            "August" => Ok(August),
248            "September" => Ok(September),
249            "October" => Ok(October),
250            "November" => Ok(November),
251            "December" => Ok(December),
252            _ => Err(error::InvalidVariant),
253        }
254    }
255}
256
257impl From<Month> for u8 {
258    fn from(month: Month) -> Self {
259        month as _
260    }
261}
262
263impl TryFrom<u8> for Month {
264    type Error = error::ComponentRange;
265
266    fn try_from(value: u8) -> Result<Self, Self::Error> {
267        match NonZeroU8::new(value) {
268            Some(value) => Self::from_number(value),
269            None => Err(error::ComponentRange {
270                name: "month",
271                minimum: 1,
272                maximum: 12,
273                value: 0,
274                conditional_range: false,
275            }),
276        }
277    }
278}