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