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