devela/phys/time/calendar/
weekday.rs

1// devela::phys::time::calendar::week
2//
3//!
4//
5
6use crate::{Display, FmtResult, Formatter, FromStr};
7#[allow(clippy::enum_glob_use)]
8use Weekday::*;
9
10/// The days of the week.
11#[repr(u8)]
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum Weekday {
14    /// The first day of the week, according to the ISO-8601 standard.
15    ///
16    /// # Etymology
17    /// The name Monday comes from the Old English word “Monandæg”,
18    /// which means “Moon’s day”.
19    Monday = 0,
20
21    ///
22    /// # Etymology
23    /// The name Tuesday comes from the Old English word “Tiwesdæg”, which means
24    /// “Tiw’s day”. Tiw was an Anglo-Saxon god associated with war and combat.
25    Tuesday,
26
27    ///
28    /// # Etymology
29    /// The name Wednesday comes from the Old English word “Wodnesdæg”, which
30    /// means “Woden’s day”. Woden was the chief god in Norse mythology,
31    /// associated with wisdom, war, and death.
32    Wednesday,
33
34    ///
35    /// # Etymology
36    /// The name Thursday comes from the Old English word “Þunresdæg”, which
37    /// means “Thor’s day”. Thor was the Norse god of thunder and lightning.
38    Thursday,
39
40    ///
41    /// # Etymology
42    /// The name Friday comes from the Old English word “Frīgedæg”, which means
43    /// “Frige’s day”. Frige was an Anglo-Saxon goddess associated with love,
44    /// fertility, and domestic life.
45    Friday,
46
47    ///
48    /// # Etymology
49    /// The name Saturday comes from the Latin word “Saturni dies”, which means
50    /// “Saturn’s day”. Saturn was the Roman god of agriculture and wealth.
51    Saturday,
52
53    ///
54    /// # Etymology
55    /// The name Sunday comes from the Old English word “Sunandæg”, which means
56    /// “Sun’s day”.
57    Sunday,
58}
59
60impl Weekday {
61    /// The number of weekdays in a week.
62    pub const COUNT: usize = 7;
63
64    /// Returns the previous weekday.
65    pub const fn previous(self) -> Weekday {
66        self.previous_nth(1)
67    }
68
69    /// Returns the previous `nth` weekday.
70    pub const fn previous_nth(self, nth: usize) -> Weekday {
71        Self::from_monday_index_unchecked(self.index_from_monday().wrapping_sub(nth) % Self::COUNT)
72    }
73
74    /// Returns the next weekday,
75    pub const fn next(self) -> Weekday {
76        self.next_nth(1)
77    }
78
79    /// Returns the next `nth` weekday.
80    pub const fn next_nth(self, nth: usize) -> Weekday {
81        Self::from_monday_index_unchecked(self.index_from_monday().wrapping_add(nth) % Self::COUNT)
82    }
83}
84
85/// # from Monday
86impl Weekday {
87    /* to number */
88
89    /// Returns the weekday number from `Monday=1` to `Sunday=7`.
90    pub const fn number_from_monday(self) -> u8 {
91        self.index_from_monday() as u8 + 1
92    }
93
94    /// Returns the weekday index from `Monday=0` to `Sunday=6`.
95    pub const fn index_from_monday(self) -> usize {
96        self as _
97    }
98
99    /// Returns a weekday from its counting number, from `Monday=1` to `Sunday=7`.
100    ///
101    /// # Errors
102    /// `if n < 1 || n > 7`
103    pub const fn from_monday_number(n: u8) -> Result<Weekday, &'static str> {
104        match n {
105            1 => Ok(Monday),
106            2 => Ok(Tuesday),
107            3 => Ok(Wednesday),
108            4 => Ok(Thursday),
109            5 => Ok(Friday),
110            6 => Ok(Saturday),
111            7 => Ok(Sunday),
112            _ => Err("The weekday number must be between 1 and 7."),
113        }
114    }
115
116    /// Returns a weekday from its index, from `Monday=0` to `Sunday=6`.
117    ///
118    /// # Errors
119    /// `if index > 6`
120    pub const fn from_monday_index(index: usize) -> Result<Weekday, &'static str> {
121        match index {
122            0 => Ok(Monday),
123            1 => Ok(Tuesday),
124            2 => Ok(Wednesday),
125            3 => Ok(Thursday),
126            4 => Ok(Friday),
127            5 => Ok(Saturday),
128            6 => Ok(Sunday),
129            _ => Err("The weekday number must be between 0 and 6."),
130        }
131    }
132
133    /// Returns a weekday from its index, from `Monday=0` to `Sunday=6`.
134    ///
135    /// # Panics
136    /// `if index > 6`
137    pub const fn from_monday_index_unchecked(index: usize) -> Self {
138        match index {
139            0 => Monday,
140            1 => Tuesday,
141            2 => Wednesday,
142            3 => Thursday,
143            4 => Friday,
144            5 => Saturday,
145            6 => Sunday,
146            _ => panic!("The weekday number must be between 0 and 6."),
147        }
148    }
149}
150
151/// # from Sunday
152impl Weekday {
153    /// Returns the weekday number from `Sunday=1` to `Monday=7`.
154    pub const fn number_from_sunday(self) -> u8 {
155        self.index_from_sunday() as u8 + 1
156    }
157
158    /// Returns the weekday index from `Sunday=0` to `Monday=6`.
159    pub const fn index_from_sunday(self) -> usize {
160        match self {
161            Monday => 1,
162            Tuesday => 2,
163            Wednesday => 3,
164            Thursday => 4,
165            Friday => 5,
166            Saturday => 6,
167            Sunday => 0,
168        }
169    }
170
171    /// Returns a weekday from its counting number, from `Sunday=1` to `Monday=7`.
172    ///
173    /// # Errors
174    /// `if n < 1 || n > 7`
175    pub const fn from_sunday_number(n: u8) -> Result<Weekday, &'static str> {
176        match n {
177            1 => Ok(Sunday),
178            2 => Ok(Monday),
179            3 => Ok(Tuesday),
180            4 => Ok(Wednesday),
181            5 => Ok(Thursday),
182            6 => Ok(Friday),
183            7 => Ok(Saturday),
184            _ => Err("The weekday number must be between 1 and 7."),
185        }
186    }
187
188    /// Returns a weekday from its index, from `Sunday=0` to `Monday=6`.
189    ///
190    /// # Errors
191    /// `if index > 6`
192    pub const fn from_sunday_index(index: usize) -> Result<Weekday, &'static str> {
193        match index {
194            0 => Ok(Sunday),
195            1 => Ok(Monday),
196            2 => Ok(Tuesday),
197            3 => Ok(Wednesday),
198            4 => Ok(Thursday),
199            5 => Ok(Friday),
200            6 => Ok(Saturday),
201            _ => Err("The weekday number must be between 0 and 6."),
202        }
203    }
204
205    /// Returns a weekday from its index, from `Sunday=0` to `Monday=6`.
206    ///
207    /// # Panics
208    /// `if index > 6`
209    pub const fn from_sunday_index_unchecked(index: usize) -> Self {
210        match index {
211            0 => Sunday,
212            1 => Monday,
213            2 => Tuesday,
214            3 => Wednesday,
215            4 => Thursday,
216            5 => Friday,
217            6 => Saturday,
218            _ => panic!("The weekday number must be between 0 and 6."),
219        }
220    }
221}
222
223/// # abbreviations & representations
224#[allow(missing_docs, non_upper_case_globals)]
225impl Weekday {
226    /// Returns the 3-letter abbreviated weekday name, in ASCII, UpperCamelCase.
227    pub fn abbr3(self) -> &'static str {
228        match self {
229            Monday => "Mon",
230            Tuesday => "Tue",
231            Wednesday => "Wed",
232            Thursday => "Thu",
233            Friday => "Fri",
234            Saturday => "Sat",
235            Sunday => "Sun",
236        }
237    }
238
239    pub const Mon: Weekday = Weekday::Monday;
240    pub const Tue: Weekday = Weekday::Tuesday;
241    pub const Wed: Weekday = Weekday::Wednesday;
242    pub const Thu: Weekday = Weekday::Thursday;
243    pub const Fri: Weekday = Weekday::Friday;
244    pub const Sat: Weekday = Weekday::Saturday;
245    pub const Sun: Weekday = Weekday::Sunday;
246
247    /// Returns the 2-letter abbreviated weekday name, in ASCII, UPPERCASE.
248    pub fn abbr2(self) -> &'static str {
249        match self {
250            Monday => "MO",
251            Tuesday => "TU",
252            Wednesday => "WE",
253            Thursday => "TH",
254            Friday => "FR",
255            Saturday => "SA",
256            Sunday => "SU",
257        }
258    }
259
260    pub const MO: Weekday = Weekday::Monday;
261    pub const TU: Weekday = Weekday::Tuesday;
262    pub const WE: Weekday = Weekday::Wednesday;
263    pub const TH: Weekday = Weekday::Thursday;
264    pub const FR: Weekday = Weekday::Friday;
265    pub const SA: Weekday = Weekday::Saturday;
266    pub const SU: Weekday = Weekday::Sunday;
267
268    /// Returns the 1-letter abbreviated weekday name, in ASCII, UPPERCASE.
269    pub fn abbr1(self) -> &'static str {
270        match self {
271            Monday => "M",
272            Tuesday => "T",
273            Wednesday => "W",
274            Thursday => "H",
275            Friday => "F",
276            Saturday => "A",
277            Sunday => "U",
278        }
279    }
280
281    pub const M: Weekday = Weekday::Monday;
282    pub const T: Weekday = Weekday::Tuesday;
283    pub const W: Weekday = Weekday::Wednesday;
284    pub const H: Weekday = Weekday::Thursday;
285    pub const F: Weekday = Weekday::Friday;
286    pub const A: Weekday = Weekday::Saturday;
287    pub const U: Weekday = Weekday::Sunday;
288
289    /// Returns the emoji associated to the weekday.
290    ///
291    /// These are: 🌕, 🏹, 🧙, ⚡, 💕, 💰, 🌞.
292    ///
293    /// Full Moon, Bow and Arrow, Mage, Lightning Bolt, Two Hearts, Money Bag,
294    /// and Sun.
295    ///
296    /// # Examples
297    /// ```
298    /// # use devela::Weekday;
299    /// assert_eq![Weekday::Thursday.emoji(), '⚡'];
300    /// ```
301    pub const fn emoji(self) -> char {
302        match self {
303            // Full Moon,
304            Monday => '🌕',
305            // Bow and Arrow.
306            Tuesday => '🏹',
307            // Mage.
308            Wednesday => '🧙',
309            // Lightning Bolt.
310            Thursday => '⚡',
311            // Two Hearts.
312            Friday => '💕',
313            // .
314            Saturday => '💰',
315            // Sun
316            Sunday => '🌞',
317        }
318    }
319
320    /// Returns the char of the associated planet of Helenistic astrology.
321    ///
322    /// These are: ☽, ♂, ☿, ♃, ♀, ♄, ☀.
323    ///
324    /// # Examples
325    /// ```
326    /// # use devela::Weekday;
327    /// assert_eq![Weekday::Thursday.planet(), '♃'];
328    /// ```
329    pub const fn planet(self) -> char {
330        match self {
331            // Moon.
332            Monday => '☽',
333            // Mars.
334            Tuesday => '♂',
335            // Mercury.
336            Wednesday => '☿',
337            // Jupiter.
338            Thursday => '♃',
339            // Venus.
340            Friday => '♀',
341            // Saturn.
342            Saturday => '♄',
343            // Sun.
344            Sunday => '☀',
345        }
346    }
347
348    /// Returns the name of the associated planet of Helenistic astrology.
349    ///
350    /// These are: Moon, Mars, Mercury, Jupiter, Venus, Saturn and Sun.
351    ///
352    /// # Examples
353    /// ```
354    /// # use devela::Weekday;
355    /// assert_eq![Weekday::Thursday.planet_name(), "Jupiter"];
356    /// ```
357    pub const fn planet_name(self) -> &'static str {
358        match self {
359            Monday => "Moon",
360            Tuesday => "Mars",
361            Wednesday => "Mercury",
362            Thursday => "Jupiter",
363            Friday => "Venus",
364            Saturday => "Saturn",
365            Sunday => "Sun",
366        }
367    }
368}
369
370impl Display for Weekday {
371    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
372        f.write_str(match self {
373            Monday => "Monday",
374            Tuesday => "Tuesday",
375            Wednesday => "Wednesday",
376            Thursday => "Thursday",
377            Friday => "Friday",
378            Saturday => "Saturday",
379            Sunday => "Sunday",
380        })
381    }
382}
383
384/// Returns a `Weekday` from a string containing either the full weekday name,
385/// or any of the weekday ASCII abbreviations.
386impl FromStr for Weekday {
387    type Err = &'static str;
388
389    fn from_str(s: &str) -> Result<Weekday, Self::Err> {
390        // full name
391        if s.eq_ignore_ascii_case("Monday") {
392            Ok(Monday)
393        } else if s.eq_ignore_ascii_case("Tuesday") {
394            Ok(Tuesday)
395        } else if s.eq_ignore_ascii_case("Wednesday") {
396            Ok(Wednesday)
397        } else if s.eq_ignore_ascii_case("Thursday") {
398            Ok(Thursday)
399        } else if s.eq_ignore_ascii_case("Friday") {
400            Ok(Friday)
401        } else if s.eq_ignore_ascii_case("Saturday") {
402            Ok(Saturday)
403        } else if s.eq_ignore_ascii_case("Sunday") {
404            Ok(Sunday)
405        // abbr3
406        } else if s.eq_ignore_ascii_case("Mon") {
407            Ok(Monday)
408        } else if s.eq_ignore_ascii_case("Tue") {
409            Ok(Tuesday)
410        } else if s.eq_ignore_ascii_case("Wed") {
411            Ok(Wednesday)
412        } else if s.eq_ignore_ascii_case("Thu") {
413            Ok(Thursday)
414        } else if s.eq_ignore_ascii_case("Fri") {
415            Ok(Friday)
416        } else if s.eq_ignore_ascii_case("Sat") {
417            Ok(Saturday)
418        } else if s.eq_ignore_ascii_case("Sun") {
419            Ok(Sunday)
420        // abbr2
421        } else if s.eq_ignore_ascii_case("MO") {
422            Ok(Monday)
423        } else if s.eq_ignore_ascii_case("TU") {
424            Ok(Tuesday)
425        } else if s.eq_ignore_ascii_case("WE") {
426            Ok(Wednesday)
427        } else if s.eq_ignore_ascii_case("TH") {
428            Ok(Thursday)
429        } else if s.eq_ignore_ascii_case("FR") {
430            Ok(Friday)
431        } else if s.eq_ignore_ascii_case("SA") {
432            Ok(Saturday)
433        } else if s.eq_ignore_ascii_case("SU") {
434            Ok(Sunday)
435        // abbr1
436        } else if s.eq_ignore_ascii_case("M") {
437            Ok(Monday)
438        } else if s.eq_ignore_ascii_case("T") {
439            Ok(Tuesday)
440        } else if s.eq_ignore_ascii_case("W") {
441            Ok(Wednesday)
442        } else if s.eq_ignore_ascii_case("H") {
443            Ok(Thursday)
444        } else if s.eq_ignore_ascii_case("F") {
445            Ok(Friday)
446        } else if s.eq_ignore_ascii_case("S") {
447            Ok(Saturday)
448        } else if s.eq_ignore_ascii_case("U") {
449            Ok(Sunday)
450
451        //
452        } else {
453            Err("Invalid weekday name.")
454        }
455    }
456}