Skip to main content

time/
weekday.rs

1//! Days of the week.
2
3use core::fmt;
4use core::str::FromStr;
5
6use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
7
8use self::Weekday::*;
9use crate::error;
10use crate::iter::WeekdayIter;
11
12/// Days of the week.
13///
14/// As order is dependent on context (Sunday could be either two days after or five days before
15/// Friday), this type does not implement `PartialOrd` or `Ord`.
16#[repr(u8)]
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub enum Weekday {
19    #[expect(missing_docs)]
20    Monday,
21    #[expect(missing_docs)]
22    Tuesday,
23    #[expect(missing_docs)]
24    Wednesday,
25    #[expect(missing_docs)]
26    Thursday,
27    #[expect(missing_docs)]
28    Friday,
29    #[expect(missing_docs)]
30    Saturday,
31    #[expect(missing_docs)]
32    Sunday,
33}
34
35impl Weekday {
36    /// Get the previous weekday.
37    ///
38    /// ```rust
39    /// # use time::Weekday;
40    /// assert_eq!(Weekday::Tuesday.previous(), Weekday::Monday);
41    /// ```
42    #[inline]
43    pub const fn previous(self) -> Self {
44        match self {
45            Monday => Sunday,
46            Tuesday => Monday,
47            Wednesday => Tuesday,
48            Thursday => Wednesday,
49            Friday => Thursday,
50            Saturday => Friday,
51            Sunday => Saturday,
52        }
53    }
54
55    /// Get the next weekday.
56    ///
57    /// ```rust
58    /// # use time::Weekday;
59    /// assert_eq!(Weekday::Monday.next(), Weekday::Tuesday);
60    /// ```
61    #[inline]
62    pub const fn next(self) -> Self {
63        match self {
64            Monday => Tuesday,
65            Tuesday => Wednesday,
66            Wednesday => Thursday,
67            Thursday => Friday,
68            Friday => Saturday,
69            Saturday => Sunday,
70            Sunday => Monday,
71        }
72    }
73
74    /// Get n-th next day.
75    ///
76    /// ```rust
77    /// # use time::Weekday;
78    /// assert_eq!(Weekday::Monday.nth_next(1), Weekday::Tuesday);
79    /// assert_eq!(Weekday::Sunday.nth_next(10), Weekday::Wednesday);
80    /// ```
81    #[inline]
82    pub const fn nth_next(self, n: u8) -> Self {
83        match (self.number_days_from_monday() + n % 7) % 7 {
84            0 => Monday,
85            1 => Tuesday,
86            2 => Wednesday,
87            3 => Thursday,
88            4 => Friday,
89            5 => Saturday,
90            val => {
91                debug_assert!(val == 6);
92                Sunday
93            }
94        }
95    }
96
97    /// Get n-th previous day.
98    ///
99    /// ```rust
100    /// # use time::Weekday;
101    /// assert_eq!(Weekday::Monday.nth_prev(1), Weekday::Sunday);
102    /// assert_eq!(Weekday::Sunday.nth_prev(10), Weekday::Thursday);
103    /// ```
104    #[inline]
105    pub const fn nth_prev(self, n: u8) -> Self {
106        match self.number_days_from_monday().cast_signed() - (n % 7).cast_signed() {
107            1 | -6 => Tuesday,
108            2 | -5 => Wednesday,
109            3 | -4 => Thursday,
110            4 | -3 => Friday,
111            5 | -2 => Saturday,
112            6 | -1 => Sunday,
113            val => {
114                debug_assert!(val == 0);
115                Monday
116            }
117        }
118    }
119
120    /// Get the one-indexed number of days from Monday.
121    ///
122    /// ```rust
123    /// # use time::Weekday;
124    /// assert_eq!(Weekday::Monday.number_from_monday(), 1);
125    /// ```
126    #[doc(alias = "iso_weekday_number")]
127    #[inline]
128    pub const fn number_from_monday(self) -> u8 {
129        self.number_days_from_monday() + 1
130    }
131
132    /// Get the one-indexed number of days from Sunday.
133    ///
134    /// ```rust
135    /// # use time::Weekday;
136    /// assert_eq!(Weekday::Monday.number_from_sunday(), 2);
137    /// ```
138    #[inline]
139    pub const fn number_from_sunday(self) -> u8 {
140        self.number_days_from_sunday() + 1
141    }
142
143    /// Get the zero-indexed number of days from Monday.
144    ///
145    /// ```rust
146    /// # use time::Weekday;
147    /// assert_eq!(Weekday::Monday.number_days_from_monday(), 0);
148    /// ```
149    #[inline]
150    pub const fn number_days_from_monday(self) -> u8 {
151        self as u8
152    }
153
154    /// Get the zero-indexed number of days from Sunday.
155    ///
156    /// ```rust
157    /// # use time::Weekday;
158    /// assert_eq!(Weekday::Monday.number_days_from_sunday(), 1);
159    /// ```
160    #[inline]
161    pub const fn number_days_from_sunday(self) -> u8 {
162        match self {
163            Monday => 1,
164            Tuesday => 2,
165            Wednesday => 3,
166            Thursday => 4,
167            Friday => 5,
168            Saturday => 6,
169            Sunday => 0,
170        }
171    }
172
173    /// Create an infinite iterator starting at this weekday.
174    ///
175    /// ```rust
176    /// # use time::Weekday;
177    /// let mut iter = Weekday::iter_from(Weekday::Monday);
178    /// assert_eq!(iter.next(), Some(Weekday::Monday));
179    /// assert_eq!(iter.next(), Some(Weekday::Tuesday));
180    /// assert_eq!(iter.next(), Some(Weekday::Wednesday));
181    /// assert_eq!(iter.next(), Some(Weekday::Thursday));
182    /// assert_eq!(iter.next(), Some(Weekday::Friday));
183    /// assert_eq!(iter.next(), Some(Weekday::Saturday));
184    /// assert_eq!(iter.next(), Some(Weekday::Sunday));
185    /// assert_eq!(iter.next(), Some(Weekday::Monday));
186    /// // … continuing forever
187    /// ```
188    #[inline]
189    pub const fn iter_from(start: Self) -> WeekdayIter {
190        WeekdayIter::new(start)
191    }
192}
193
194impl SmartDisplay for Weekday {
195    type Metadata = ();
196
197    #[inline]
198    fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
199        match self {
200            Monday => Metadata::new(6, self, ()),
201            Tuesday => Metadata::new(7, self, ()),
202            Wednesday => Metadata::new(9, self, ()),
203            Thursday => Metadata::new(8, self, ()),
204            Friday => Metadata::new(6, self, ()),
205            Saturday => Metadata::new(8, self, ()),
206            Sunday => Metadata::new(6, self, ()),
207        }
208    }
209
210    #[inline]
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        f.pad(match self {
213            Monday => "Monday",
214            Tuesday => "Tuesday",
215            Wednesday => "Wednesday",
216            Thursday => "Thursday",
217            Friday => "Friday",
218            Saturday => "Saturday",
219            Sunday => "Sunday",
220        })
221    }
222}
223
224impl fmt::Display for Weekday {
225    #[inline]
226    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227        SmartDisplay::fmt(self, f)
228    }
229}
230
231impl FromStr for Weekday {
232    type Err = error::InvalidVariant;
233
234    #[inline]
235    fn from_str(s: &str) -> Result<Self, Self::Err> {
236        match s {
237            "Monday" => Ok(Monday),
238            "Tuesday" => Ok(Tuesday),
239            "Wednesday" => Ok(Wednesday),
240            "Thursday" => Ok(Thursday),
241            "Friday" => Ok(Friday),
242            "Saturday" => Ok(Saturday),
243            "Sunday" => Ok(Sunday),
244            _ => Err(error::InvalidVariant),
245        }
246    }
247}