Skip to main content

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
179impl SmartDisplay for Month {
180    type Metadata = ();
181
182    #[inline]
183    fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
184        match self {
185            January => Metadata::new(7, self, ()),
186            February => Metadata::new(8, self, ()),
187            March => Metadata::new(5, self, ()),
188            April => Metadata::new(5, self, ()),
189            May => Metadata::new(3, self, ()),
190            June => Metadata::new(4, self, ()),
191            July => Metadata::new(4, self, ()),
192            August => Metadata::new(6, self, ()),
193            September => Metadata::new(9, self, ()),
194            October => Metadata::new(7, self, ()),
195            November => Metadata::new(8, self, ()),
196            December => Metadata::new(8, self, ()),
197        }
198    }
199
200    #[inline]
201    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202        f.pad(match self {
203            January => "January",
204            February => "February",
205            March => "March",
206            April => "April",
207            May => "May",
208            June => "June",
209            July => "July",
210            August => "August",
211            September => "September",
212            October => "October",
213            November => "November",
214            December => "December",
215        })
216    }
217}
218
219impl fmt::Display for Month {
220    #[inline]
221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222        SmartDisplay::fmt(self, f)
223    }
224}
225
226impl FromStr for Month {
227    type Err = error::InvalidVariant;
228
229    #[inline]
230    fn from_str(s: &str) -> Result<Self, Self::Err> {
231        match s {
232            "January" => Ok(January),
233            "February" => Ok(February),
234            "March" => Ok(March),
235            "April" => Ok(April),
236            "May" => Ok(May),
237            "June" => Ok(June),
238            "July" => Ok(July),
239            "August" => Ok(August),
240            "September" => Ok(September),
241            "October" => Ok(October),
242            "November" => Ok(November),
243            "December" => Ok(December),
244            _ => Err(error::InvalidVariant),
245        }
246    }
247}
248
249impl From<Month> for u8 {
250    #[inline]
251    fn from(month: Month) -> Self {
252        month as Self
253    }
254}
255
256impl TryFrom<u8> for Month {
257    type Error = error::ComponentRange;
258
259    #[inline]
260    fn try_from(value: u8) -> Result<Self, Self::Error> {
261        match NonZero::new(value) {
262            Some(value) => Self::from_number(value),
263            None => Err(error::ComponentRange::unconditional("month")),
264        }
265    }
266}