time/
month.rs

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