1use crate::{Display, FmtResult, Formatter, FromStr};
7#[allow(clippy::enum_glob_use)]
8use Month::*;
9
10#[repr(u8)]
12#[allow(missing_docs)]
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
14pub enum Month {
15 January = 0,
16 February,
17 March,
18 April,
19 May,
20 June,
21 July,
22 August,
23 September,
24 October,
25 November,
26 December,
27}
28
29impl Month {
30 pub const COUNT: usize = 12;
32
33 #[allow(clippy::len_without_is_empty)]
36 pub const fn len(self, leap: bool) -> u8 {
37 match self {
38 January => 31,
39 February => 28 + leap as u8,
40 March => 31,
41 April => 30,
42 May => 31,
43 June => 30,
44 July => 31,
45 August => 31,
46 September => 30,
47 October => 31,
48 November => 30,
49 December => 31,
50 }
51 }
52
53 pub const fn previous(self) -> Month {
55 self.previous_nth(1)
56 }
57
58 pub const fn previous_nth(self, nth: usize) -> Month {
60 Self::from_index_unchecked(self.index().wrapping_sub(nth) % Self::COUNT)
61 }
62
63 pub const fn next(self) -> Month {
65 self.next_nth(1)
66 }
67
68 pub const fn next_nth(self, nth: usize) -> Month {
70 Self::from_index_unchecked(self.index().wrapping_add(nth) % Self::COUNT)
71 }
72
73 pub const fn number(self) -> u8 {
77 self.index() as u8 + 1
78 }
79
80 pub const fn index(self) -> usize {
82 self as _
83 }
84
85 pub const fn from_number(n: u8) -> Result<Month, &'static str> {
90 match n {
91 1 => Ok(January),
92 2 => Ok(February),
93 3 => Ok(March),
94 4 => Ok(April),
95 5 => Ok(May),
96 6 => Ok(June),
97 7 => Ok(July),
98 8 => Ok(August),
99 9 => Ok(September),
100 10 => Ok(October),
101 11 => Ok(November),
102 12 => Ok(December),
103 _ => Err("The month number must be between 1 and 12."),
104 }
105 }
106
107 pub const fn from_index(index: usize) -> Result<Month, &'static str> {
112 match index {
113 0 => Ok(January),
114 1 => Ok(February),
115 2 => Ok(March),
116 3 => Ok(April),
117 4 => Ok(May),
118 5 => Ok(June),
119 6 => Ok(July),
120 7 => Ok(August),
121 8 => Ok(September),
122 9 => Ok(October),
123 10 => Ok(November),
124 11 => Ok(December),
125 _ => Err("The month index must be between 0 and 11."),
126 }
127 }
128
129 pub const fn from_index_unchecked(index: usize) -> Self {
134 match index {
135 0 => January,
136 1 => February,
137 2 => March,
138 3 => April,
139 4 => May,
140 5 => June,
141 6 => July,
142 7 => August,
143 8 => September,
144 9 => October,
145 10 => November,
146 11 => December,
147 _ => panic!("The month index must be between 0 and 11."),
148 }
149 }
150}
151
152#[allow(missing_docs, non_upper_case_globals)]
154impl Month {
155 pub const fn abbr3(self) -> &'static str {
157 match self {
158 January => "Jan",
159 February => "Feb",
160 March => "Mar",
161 April => "Apr",
162 May => "May",
163 June => "Jun",
164 July => "Jul",
165 August => "Aug",
166 September => "Sep",
167 October => "Oct",
168 November => "Nov",
169 December => "Dec",
170 }
171 }
172
173 pub const Jan: Month = Month::January;
174 pub const Feb: Month = Month::February;
175 pub const Mar: Month = Month::March;
176 pub const Apr: Month = Month::April;
177 pub const May: Month = Month::May;
178 pub const Jun: Month = Month::June;
179 pub const Jul: Month = Month::July;
180 pub const Aug: Month = Month::August;
181 pub const Sep: Month = Month::September;
182 pub const Oct: Month = Month::October;
183 pub const Nov: Month = Month::November;
184 pub const Dec: Month = Month::December;
185
186 pub const fn abbr2(self) -> &'static str {
188 match self {
189 January => "JA",
190 February => "FE",
191 March => "MR",
192 April => "AP",
193 May => "MY",
194 June => "JN",
195 July => "JL",
196 August => "AU",
197 September => "SE",
198 October => "OC",
199 November => "NV",
200 December => "DE",
201 }
202 }
203
204 pub const JA: Month = Month::January;
205 pub const FE: Month = Month::February;
206 pub const MR: Month = Month::March;
207 pub const AP: Month = Month::April;
208 pub const MY: Month = Month::May;
209 pub const JN: Month = Month::June;
210 pub const JL: Month = Month::July;
211 pub const AU: Month = Month::August;
212 pub const SE: Month = Month::September;
213 pub const OC: Month = Month::October;
214 pub const NV: Month = Month::November;
215 pub const DE: Month = Month::December;
216
217 pub const fn abbr1(self) -> &'static str {
219 match self {
220 January => "J",
221 February => "F",
222 March => "R",
223 April => "P",
224 May => "Y",
225 June => "N",
226 July => "L",
227 August => "U",
228 September => "S",
229 October => "O",
230 November => "N",
231 December => "D",
232 }
233 }
234
235 pub const J: Month = Month::January;
236 pub const F: Month = Month::February;
237 pub const R: Month = Month::March;
238 pub const P: Month = Month::April;
239 pub const Y: Month = Month::May;
240 pub const N: Month = Month::June;
241 pub const L: Month = Month::July;
242 pub const U: Month = Month::August;
243 pub const S: Month = Month::September;
244 pub const O: Month = Month::October;
245 pub const V: Month = Month::November;
246 pub const D: Month = Month::December;
247
248 pub const fn emoji(self) -> char {
255 match self {
256 January => '🌺',
258 February => '🐉',
260 March => '🍀',
262 April => '🐰',
264 May => '🌼',
266 June => '🐟',
268 July => '🌞',
270 August => '🍂',
272 September => '🎃',
274 October => '🦉',
276 November => '🍁',
278 December => '🎄',
280 }
281 }
282
283 pub const fn zodiac_start(self) -> char {
296 match self {
297 January => '♑',
299 February => '♒',
301 March => '♓',
303 April => '♈',
305 May => '♉',
307 June => '♊',
309 July => '♋',
311 August => '♌',
313 September => '♍',
315 October => '♎',
317 November => '♏',
319 December => '♐',
321 }
322 }
323
324 pub const fn zodiac_start_name(self) -> &'static str {
335 match self {
336 January => "Capricorn",
337 February => "Aquarius",
338 March => "Pisces",
339 April => "Aries",
340 May => "Taurus",
341 June => "Gemini",
342 July => "Cancer",
343 August => "Leo",
344 September => "Virgo",
345 October => "Libra",
346 November => "Scorpio",
347 December => "Sagittarius",
348 }
349 }
350
351 pub const fn zodiac_end(self) -> char {
361 self.next().zodiac_start()
362 }
363
364 pub const fn zodiac_end_name(self) -> &'static str {
375 self.next().zodiac_start_name()
376 }
377}
378
379impl Display for Month {
380 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
381 f.write_str(match self {
382 January => "January",
383 February => "February",
384 March => "March",
385 April => "April",
386 May => "May",
387 June => "June",
388 July => "July",
389 August => "August",
390 September => "September",
391 October => "October",
392 November => "November",
393 December => "December",
394 })
395 }
396}
397
398impl From<Month> for u8 {
399 fn from(month: Month) -> Self {
400 month as _
401 }
402}
403
404impl FromStr for Month {
407 type Err = &'static str;
408
409 #[rustfmt::skip]
410 fn from_str(s: &str) -> Result<Month, Self::Err> {
411 if s.eq_ignore_ascii_case("January") { Ok(January)
412 } else if s.eq_ignore_ascii_case("February") { Ok(February)
413 } else if s.eq_ignore_ascii_case("March") { Ok(March)
414 } else if s.eq_ignore_ascii_case("April") { Ok(April)
415 } else if s.eq_ignore_ascii_case("May") { Ok(May)
416 } else if s.eq_ignore_ascii_case("June") { Ok(June)
417 } else if s.eq_ignore_ascii_case("July") { Ok(July)
418 } else if s.eq_ignore_ascii_case("August") { Ok(August)
419 } else if s.eq_ignore_ascii_case("September") { Ok(September)
420 } else if s.eq_ignore_ascii_case("October") { Ok(October)
421 } else if s.eq_ignore_ascii_case("November") { Ok(November)
422 } else if s.eq_ignore_ascii_case("December") { Ok(December)
423 } else if s.eq_ignore_ascii_case("Jan") { Ok(January)
425 } else if s.eq_ignore_ascii_case("Feb") { Ok(February)
426 } else if s.eq_ignore_ascii_case("Mar") { Ok(March)
427 } else if s.eq_ignore_ascii_case("Apr") { Ok(April)
428 } else if s.eq_ignore_ascii_case("Jun") { Ok(June)
430 } else if s.eq_ignore_ascii_case("Jul") { Ok(July)
431 } else if s.eq_ignore_ascii_case("Aug") { Ok(August)
432 } else if s.eq_ignore_ascii_case("Sep") { Ok(September)
433 } else if s.eq_ignore_ascii_case("Oct") { Ok(October)
434 } else if s.eq_ignore_ascii_case("Nov") { Ok(November)
435 } else if s.eq_ignore_ascii_case("Dec") { Ok(December)
436 } else if s.eq_ignore_ascii_case("JA") { Ok(January)
438 } else if s.eq_ignore_ascii_case("FE") { Ok(February)
439 } else if s.eq_ignore_ascii_case("MR") { Ok(March)
440 } else if s.eq_ignore_ascii_case("AP") { Ok(April)
441 } else if s.eq_ignore_ascii_case("MY") { Ok(May)
442 } else if s.eq_ignore_ascii_case("JN") { Ok(June)
443 } else if s.eq_ignore_ascii_case("JL") { Ok(July)
444 } else if s.eq_ignore_ascii_case("AU") { Ok(August)
445 } else if s.eq_ignore_ascii_case("SE") { Ok(September)
446 } else if s.eq_ignore_ascii_case("OC") { Ok(October)
447 } else if s.eq_ignore_ascii_case("NV") { Ok(November)
448 } else if s.eq_ignore_ascii_case("DE") { Ok(December)
449 } else if s.eq_ignore_ascii_case("J") { Ok(January)
451 } else if s.eq_ignore_ascii_case("F") { Ok(February)
452 } else if s.eq_ignore_ascii_case("R") { Ok(March)
453 } else if s.eq_ignore_ascii_case("P") { Ok(April)
454 } else if s.eq_ignore_ascii_case("Y") { Ok(May)
455 } else if s.eq_ignore_ascii_case("N") { Ok(June)
456 } else if s.eq_ignore_ascii_case("L") { Ok(July)
457 } else if s.eq_ignore_ascii_case("U") { Ok(August)
458 } else if s.eq_ignore_ascii_case("S") { Ok(September)
459 } else if s.eq_ignore_ascii_case("O") { Ok(October)
460 } else if s.eq_ignore_ascii_case("V") { Ok(November)
461 } else if s.eq_ignore_ascii_case("D") { Ok(December)
462 } else {
464 Err("Invalid month name.")
465 }
466 }
467}