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 i64,
63                conditional_message: None,
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        util::days_in_month(self, year)
76    }
77
78    /// Get the previous month.
79    ///
80    /// ```rust
81    /// # use time::Month;
82    /// assert_eq!(Month::January.previous(), Month::December);
83    /// ```
84    pub const fn previous(self) -> Self {
85        match self {
86            January => December,
87            February => January,
88            March => February,
89            April => March,
90            May => April,
91            June => May,
92            July => June,
93            August => July,
94            September => August,
95            October => September,
96            November => October,
97            December => November,
98        }
99    }
100
101    /// Get the next month.
102    ///
103    /// ```rust
104    /// # use time::Month;
105    /// assert_eq!(Month::January.next(), Month::February);
106    /// ```
107    pub const fn next(self) -> Self {
108        match self {
109            January => February,
110            February => March,
111            March => April,
112            April => May,
113            May => June,
114            June => July,
115            July => August,
116            August => September,
117            September => October,
118            October => November,
119            November => December,
120            December => January,
121        }
122    }
123
124    /// Get n-th next month.
125    ///
126    /// ```rust
127    /// # use time::Month;
128    /// assert_eq!(Month::January.nth_next(4), Month::May);
129    /// assert_eq!(Month::July.nth_next(9), Month::April);
130    /// ```
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    pub const fn nth_prev(self, n: u8) -> Self {
159        match self as i8 - 1 - (n % 12) as i8 {
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    #[non_exhaustive]
181    #[derive(Debug, Clone, Copy)]
182    pub struct MonthMetadata;
183}
184use private::MonthMetadata;
185
186impl SmartDisplay for Month {
187    type Metadata = MonthMetadata;
188
189    fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
190        match self {
191            January => Metadata::new(7, self, MonthMetadata),
192            February => Metadata::new(8, self, MonthMetadata),
193            March => Metadata::new(5, self, MonthMetadata),
194            April => Metadata::new(5, self, MonthMetadata),
195            May => Metadata::new(3, self, MonthMetadata),
196            June => Metadata::new(4, self, MonthMetadata),
197            July => Metadata::new(4, self, MonthMetadata),
198            August => Metadata::new(6, self, MonthMetadata),
199            September => Metadata::new(9, self, MonthMetadata),
200            October => Metadata::new(7, self, MonthMetadata),
201            November => Metadata::new(8, self, MonthMetadata),
202            December => Metadata::new(8, self, MonthMetadata),
203        }
204    }
205
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        f.pad(match self {
208            January => "January",
209            February => "February",
210            March => "March",
211            April => "April",
212            May => "May",
213            June => "June",
214            July => "July",
215            August => "August",
216            September => "September",
217            October => "October",
218            November => "November",
219            December => "December",
220        })
221    }
222}
223
224impl fmt::Display for Month {
225    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226        SmartDisplay::fmt(self, f)
227    }
228}
229
230impl FromStr for Month {
231    type Err = error::InvalidVariant;
232
233    fn from_str(s: &str) -> Result<Self, Self::Err> {
234        match s {
235            "January" => Ok(January),
236            "February" => Ok(February),
237            "March" => Ok(March),
238            "April" => Ok(April),
239            "May" => Ok(May),
240            "June" => Ok(June),
241            "July" => Ok(July),
242            "August" => Ok(August),
243            "September" => Ok(September),
244            "October" => Ok(October),
245            "November" => Ok(November),
246            "December" => Ok(December),
247            _ => Err(error::InvalidVariant),
248        }
249    }
250}
251
252impl From<Month> for u8 {
253    fn from(month: Month) -> Self {
254        month as Self
255    }
256}
257
258impl TryFrom<u8> for Month {
259    type Error = error::ComponentRange;
260
261    fn try_from(value: u8) -> Result<Self, Self::Error> {
262        match NonZeroU8::new(value) {
263            Some(value) => Self::from_number(value),
264            None => Err(error::ComponentRange {
265                name: "month",
266                minimum: 1,
267                maximum: 12,
268                value: 0,
269                conditional_message: None,
270            }),
271        }
272    }
273}