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