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