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            _ => Err(error::ComponentRange::unconditional("month")),
60        }
61    }
62
63    /// Get the number of days in the month of a given year.
64    ///
65    /// ```rust
66    /// # use time::Month;
67    /// assert_eq!(Month::February.length(2020), 29);
68    /// ```
69    #[inline]
70    pub const fn length(self, year: i32) -> u8 {
71        util::days_in_month(self, year)
72    }
73
74    /// Get the previous month.
75    ///
76    /// ```rust
77    /// # use time::Month;
78    /// assert_eq!(Month::January.previous(), Month::December);
79    /// ```
80    #[inline]
81    pub const fn previous(self) -> Self {
82        match self {
83            January => December,
84            February => January,
85            March => February,
86            April => March,
87            May => April,
88            June => May,
89            July => June,
90            August => July,
91            September => August,
92            October => September,
93            November => October,
94            December => November,
95        }
96    }
97
98    /// Get the next month.
99    ///
100    /// ```rust
101    /// # use time::Month;
102    /// assert_eq!(Month::January.next(), Month::February);
103    /// ```
104    #[inline]
105    pub const fn next(self) -> Self {
106        match self {
107            January => February,
108            February => March,
109            March => April,
110            April => May,
111            May => June,
112            June => July,
113            July => August,
114            August => September,
115            September => October,
116            October => November,
117            November => December,
118            December => January,
119        }
120    }
121
122    /// Get n-th next month.
123    ///
124    /// ```rust
125    /// # use time::Month;
126    /// assert_eq!(Month::January.nth_next(4), Month::May);
127    /// assert_eq!(Month::July.nth_next(9), Month::April);
128    /// ```
129    #[inline]
130    pub const fn nth_next(self, n: u8) -> Self {
131        match (self as u8 - 1 + n % 12) % 12 {
132            0 => January,
133            1 => February,
134            2 => March,
135            3 => April,
136            4 => May,
137            5 => June,
138            6 => July,
139            7 => August,
140            8 => September,
141            9 => October,
142            10 => November,
143            val => {
144                debug_assert!(val == 11);
145                December
146            }
147        }
148    }
149
150    /// Get n-th previous month.
151    ///
152    /// ```rust
153    /// # use time::Month;
154    /// assert_eq!(Month::January.nth_prev(4), Month::September);
155    /// assert_eq!(Month::July.nth_prev(9), Month::October);
156    /// ```
157    #[inline]
158    pub const fn nth_prev(self, n: u8) -> Self {
159        match self as i8 - 1 - (n % 12).cast_signed() {
160            1 | -11 => February,
161            2 | -10 => March,
162            3 | -9 => April,
163            4 | -8 => May,
164            5 | -7 => June,
165            6 | -6 => July,
166            7 | -5 => August,
167            8 | -4 => September,
168            9 | -3 => October,
169            10 | -2 => November,
170            11 | -1 => December,
171            val => {
172                debug_assert!(val == 0);
173                January
174            }
175        }
176    }
177}
178
179mod private {
180    /// Metadata for `Month`.
181    #[non_exhaustive]
182    #[derive(Debug, Clone, Copy)]
183    pub struct MonthMetadata;
184}
185use private::MonthMetadata;
186
187impl SmartDisplay for Month {
188    type Metadata = MonthMetadata;
189
190    #[inline]
191    fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
192        match self {
193            January => Metadata::new(7, self, MonthMetadata),
194            February => Metadata::new(8, self, MonthMetadata),
195            March => Metadata::new(5, self, MonthMetadata),
196            April => Metadata::new(5, self, MonthMetadata),
197            May => Metadata::new(3, self, MonthMetadata),
198            June => Metadata::new(4, self, MonthMetadata),
199            July => Metadata::new(4, self, MonthMetadata),
200            August => Metadata::new(6, self, MonthMetadata),
201            September => Metadata::new(9, self, MonthMetadata),
202            October => Metadata::new(7, self, MonthMetadata),
203            November => Metadata::new(8, self, MonthMetadata),
204            December => Metadata::new(8, self, MonthMetadata),
205        }
206    }
207
208    #[inline]
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        f.pad(match self {
211            January => "January",
212            February => "February",
213            March => "March",
214            April => "April",
215            May => "May",
216            June => "June",
217            July => "July",
218            August => "August",
219            September => "September",
220            October => "October",
221            November => "November",
222            December => "December",
223        })
224    }
225}
226
227impl fmt::Display for Month {
228    #[inline]
229    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230        SmartDisplay::fmt(self, f)
231    }
232}
233
234impl FromStr for Month {
235    type Err = error::InvalidVariant;
236
237    #[inline]
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    #[inline]
259    fn from(month: Month) -> Self {
260        month as Self
261    }
262}
263
264impl TryFrom<u8> for Month {
265    type Error = error::ComponentRange;
266
267    #[inline]
268    fn try_from(value: u8) -> Result<Self, Self::Error> {
269        match NonZero::new(value) {
270            Some(value) => Self::from_number(value),
271            None => Err(error::ComponentRange::unconditional("month")),
272        }
273    }
274}