Coverage Report

Created: 2025-07-23 06:18

/rust/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.35/src/weekday.rs
Line
Count
Source (jump to first uncovered line)
1
use core::fmt;
2
3
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
4
use rkyv::{Archive, Deserialize, Serialize};
5
6
use crate::OutOfRange;
7
8
/// The day of week.
9
///
10
/// The order of the days of week depends on the context.
11
/// (This is why this type does *not* implement `PartialOrd` or `Ord` traits.)
12
/// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result.
13
///
14
/// # Example
15
/// ```
16
/// use chrono::Weekday;
17
///
18
/// let monday = "Monday".parse::<Weekday>().unwrap();
19
/// assert_eq!(monday, Weekday::Mon);
20
///
21
/// let sunday = Weekday::try_from(6).unwrap();
22
/// assert_eq!(sunday, Weekday::Sun);
23
///
24
/// assert_eq!(sunday.num_days_from_monday(), 6); // starts counting with Monday = 0
25
/// assert_eq!(sunday.number_from_monday(), 7); // starts counting with Monday = 1
26
/// assert_eq!(sunday.num_days_from_sunday(), 0); // starts counting with Sunday = 0
27
/// assert_eq!(sunday.number_from_sunday(), 1); // starts counting with Sunday = 1
28
///
29
/// assert_eq!(sunday.succ(), monday);
30
/// assert_eq!(sunday.pred(), Weekday::Sat);
31
/// ```
32
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
33
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
34
#[cfg_attr(
35
    any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
36
    derive(Archive, Deserialize, Serialize),
37
    archive(compare(PartialEq)),
38
    archive_attr(derive(Clone, Copy, PartialEq, Eq, Debug, Hash))
39
)]
40
#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
41
#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(arbitrary::Arbitrary))]
42
pub enum Weekday {
43
    /// Monday.
44
    Mon = 0,
45
    /// Tuesday.
46
    Tue = 1,
47
    /// Wednesday.
48
    Wed = 2,
49
    /// Thursday.
50
    Thu = 3,
51
    /// Friday.
52
    Fri = 4,
53
    /// Saturday.
54
    Sat = 5,
55
    /// Sunday.
56
    Sun = 6,
57
}
58
59
impl Weekday {
60
    /// The next day in the week.
61
    ///
62
    /// `w`:        | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
63
    /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
64
    /// `w.succ()`: | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` | `Mon`
65
    #[inline]
66
    #[must_use]
67
0
    pub const fn succ(&self) -> Weekday {
68
0
        match *self {
69
0
            Weekday::Mon => Weekday::Tue,
70
0
            Weekday::Tue => Weekday::Wed,
71
0
            Weekday::Wed => Weekday::Thu,
72
0
            Weekday::Thu => Weekday::Fri,
73
0
            Weekday::Fri => Weekday::Sat,
74
0
            Weekday::Sat => Weekday::Sun,
75
0
            Weekday::Sun => Weekday::Mon,
76
        }
77
0
    }
78
79
    /// The previous day in the week.
80
    ///
81
    /// `w`:        | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
82
    /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
83
    /// `w.pred()`: | `Sun` | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat`
84
    #[inline]
85
    #[must_use]
86
0
    pub const fn pred(&self) -> Weekday {
87
0
        match *self {
88
0
            Weekday::Mon => Weekday::Sun,
89
0
            Weekday::Tue => Weekday::Mon,
90
0
            Weekday::Wed => Weekday::Tue,
91
0
            Weekday::Thu => Weekday::Wed,
92
0
            Weekday::Fri => Weekday::Thu,
93
0
            Weekday::Sat => Weekday::Fri,
94
0
            Weekday::Sun => Weekday::Sat,
95
        }
96
0
    }
97
98
    /// Returns a day-of-week number starting from Monday = 1. (ISO 8601 weekday number)
99
    ///
100
    /// `w`:                      | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
101
    /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
102
    /// `w.number_from_monday()`: | 1     | 2     | 3     | 4     | 5     | 6     | 7
103
    #[inline]
104
0
    pub const fn number_from_monday(&self) -> u32 {
105
0
        self.num_days_from(Weekday::Mon) + 1
106
0
    }
107
108
    /// Returns a day-of-week number starting from Sunday = 1.
109
    ///
110
    /// `w`:                      | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
111
    /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
112
    /// `w.number_from_sunday()`: | 2     | 3     | 4     | 5     | 6     | 7     | 1
113
    #[inline]
114
0
    pub const fn number_from_sunday(&self) -> u32 {
115
0
        self.num_days_from(Weekday::Sun) + 1
116
0
    }
Unexecuted instantiation: <chrono::weekday::Weekday>::number_from_sunday
Unexecuted instantiation: <chrono::weekday::Weekday>::number_from_sunday
117
118
    /// Returns a day-of-week number starting from Monday = 0.
119
    ///
120
    /// `w`:                        | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
121
    /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
122
    /// `w.num_days_from_monday()`: | 0     | 1     | 2     | 3     | 4     | 5     | 6
123
    ///
124
    /// # Example
125
    ///
126
    #[cfg_attr(not(feature = "clock"), doc = "```ignore")]
127
    #[cfg_attr(feature = "clock", doc = "```rust")]
128
    /// # use chrono::{Local, Datelike};
129
    /// // MTWRFSU is occasionally used as a single-letter abbreviation of the weekdays.
130
    /// // Use `num_days_from_monday` to index into the array.
131
    /// const MTWRFSU: [char; 7] = ['M', 'T', 'W', 'R', 'F', 'S', 'U'];
132
    ///
133
    /// let today = Local::now().weekday();
134
    /// println!("{}", MTWRFSU[today.num_days_from_monday() as usize]);
135
    /// ```
136
    #[inline]
137
0
    pub const fn num_days_from_monday(&self) -> u32 {
138
0
        self.num_days_from(Weekday::Mon)
139
0
    }
140
141
    /// Returns a day-of-week number starting from Sunday = 0.
142
    ///
143
    /// `w`:                        | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun`
144
    /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
145
    /// `w.num_days_from_sunday()`: | 1     | 2     | 3     | 4     | 5     | 6     | 0
146
    #[inline]
147
0
    pub const fn num_days_from_sunday(&self) -> u32 {
148
0
        self.num_days_from(Weekday::Sun)
149
0
    }
150
151
    /// Returns a day-of-week number starting from the parameter `day` (D) = 0.
152
    ///
153
    /// `w`:                        | `D`   | `D+1` | `D+2` | `D+3` | `D+4` | `D+5` | `D+6`
154
    /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
155
    /// `w.num_days_from(wd)`:      | 0     | 1     | 2     | 3     | 4     | 5     | 6
156
    #[inline]
157
0
    pub(crate) const fn num_days_from(&self, day: Weekday) -> u32 {
158
0
        (*self as u32 + 7 - day as u32) % 7
159
0
    }
Unexecuted instantiation: <chrono::weekday::Weekday>::num_days_from
Unexecuted instantiation: <chrono::weekday::Weekday>::num_days_from
160
}
161
162
impl fmt::Display for Weekday {
163
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164
0
        f.write_str(match *self {
165
0
            Weekday::Mon => "Mon",
166
0
            Weekday::Tue => "Tue",
167
0
            Weekday::Wed => "Wed",
168
0
            Weekday::Thu => "Thu",
169
0
            Weekday::Fri => "Fri",
170
0
            Weekday::Sat => "Sat",
171
0
            Weekday::Sun => "Sun",
172
        })
173
0
    }
174
}
175
176
/// Any weekday can be represented as an integer from 0 to 6, which equals to
177
/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation.
178
/// Do not heavily depend on this though; use explicit methods whenever possible.
179
impl TryFrom<u8> for Weekday {
180
    type Error = OutOfRange;
181
182
0
    fn try_from(value: u8) -> Result<Self, Self::Error> {
183
0
        match value {
184
0
            0 => Ok(Weekday::Mon),
185
0
            1 => Ok(Weekday::Tue),
186
0
            2 => Ok(Weekday::Wed),
187
0
            3 => Ok(Weekday::Thu),
188
0
            4 => Ok(Weekday::Fri),
189
0
            5 => Ok(Weekday::Sat),
190
0
            6 => Ok(Weekday::Sun),
191
0
            _ => Err(OutOfRange::new()),
192
        }
193
0
    }
194
}
195
196
/// Any weekday can be represented as an integer from 0 to 6, which equals to
197
/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation.
198
/// Do not heavily depend on this though; use explicit methods whenever possible.
199
impl num_traits::FromPrimitive for Weekday {
200
    #[inline]
201
0
    fn from_i64(n: i64) -> Option<Weekday> {
202
0
        match n {
203
0
            0 => Some(Weekday::Mon),
204
0
            1 => Some(Weekday::Tue),
205
0
            2 => Some(Weekday::Wed),
206
0
            3 => Some(Weekday::Thu),
207
0
            4 => Some(Weekday::Fri),
208
0
            5 => Some(Weekday::Sat),
209
0
            6 => Some(Weekday::Sun),
210
0
            _ => None,
211
        }
212
0
    }
213
214
    #[inline]
215
0
    fn from_u64(n: u64) -> Option<Weekday> {
216
0
        match n {
217
0
            0 => Some(Weekday::Mon),
218
0
            1 => Some(Weekday::Tue),
219
0
            2 => Some(Weekday::Wed),
220
0
            3 => Some(Weekday::Thu),
221
0
            4 => Some(Weekday::Fri),
222
0
            5 => Some(Weekday::Sat),
223
0
            6 => Some(Weekday::Sun),
224
0
            _ => None,
225
        }
226
0
    }
227
}
228
229
/// An error resulting from reading `Weekday` value with `FromStr`.
230
#[derive(Clone, PartialEq, Eq)]
231
pub struct ParseWeekdayError {
232
    pub(crate) _dummy: (),
233
}
234
235
#[cfg(feature = "std")]
236
impl std::error::Error for ParseWeekdayError {}
237
238
impl fmt::Display for ParseWeekdayError {
239
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240
0
        f.write_fmt(format_args!("{:?}", self))
241
0
    }
242
}
243
244
impl fmt::Debug for ParseWeekdayError {
245
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246
0
        write!(f, "ParseWeekdayError {{ .. }}")
247
0
    }
248
}
249
250
// the actual `FromStr` implementation is in the `format` module to leverage the existing code
251
252
#[cfg(feature = "serde")]
253
mod weekday_serde {
254
    use super::Weekday;
255
    use core::fmt;
256
    use serde::{de, ser};
257
258
    impl ser::Serialize for Weekday {
259
0
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
260
0
        where
261
0
            S: ser::Serializer,
262
0
        {
263
0
            serializer.collect_str(&self)
264
0
        }
265
    }
266
267
    struct WeekdayVisitor;
268
269
    impl<'de> de::Visitor<'de> for WeekdayVisitor {
270
        type Value = Weekday;
271
272
0
        fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
273
0
            f.write_str("Weekday")
274
0
        }
275
276
0
        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
277
0
        where
278
0
            E: de::Error,
279
0
        {
280
0
            value.parse().map_err(|_| E::custom("short or long weekday names expected"))
281
0
        }
282
    }
283
284
    impl<'de> de::Deserialize<'de> for Weekday {
285
0
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
286
0
        where
287
0
            D: de::Deserializer<'de>,
288
0
        {
289
0
            deserializer.deserialize_str(WeekdayVisitor)
290
0
        }
291
    }
292
}
293
294
#[cfg(test)]
295
mod tests {
296
    use super::Weekday;
297
298
    #[test]
299
    fn test_num_days_from() {
300
        for i in 0..7 {
301
            let base_day = Weekday::try_from(i).unwrap();
302
303
            assert_eq!(base_day.num_days_from_monday(), base_day.num_days_from(Weekday::Mon));
304
            assert_eq!(base_day.num_days_from_sunday(), base_day.num_days_from(Weekday::Sun));
305
306
            assert_eq!(base_day.num_days_from(base_day), 0);
307
308
            assert_eq!(base_day.num_days_from(base_day.pred()), 1);
309
            assert_eq!(base_day.num_days_from(base_day.pred().pred()), 2);
310
            assert_eq!(base_day.num_days_from(base_day.pred().pred().pred()), 3);
311
            assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred()), 4);
312
            assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred().pred()), 5);
313
            assert_eq!(
314
                base_day.num_days_from(base_day.pred().pred().pred().pred().pred().pred()),
315
                6
316
            );
317
318
            assert_eq!(base_day.num_days_from(base_day.succ()), 6);
319
            assert_eq!(base_day.num_days_from(base_day.succ().succ()), 5);
320
            assert_eq!(base_day.num_days_from(base_day.succ().succ().succ()), 4);
321
            assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ()), 3);
322
            assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ().succ()), 2);
323
            assert_eq!(
324
                base_day.num_days_from(base_day.succ().succ().succ().succ().succ().succ()),
325
                1
326
            );
327
        }
328
    }
329
330
    #[test]
331
    #[cfg(feature = "serde")]
332
    fn test_serde_serialize() {
333
        use serde_json::to_string;
334
        use Weekday::*;
335
336
        let cases: Vec<(Weekday, &str)> = vec![
337
            (Mon, "\"Mon\""),
338
            (Tue, "\"Tue\""),
339
            (Wed, "\"Wed\""),
340
            (Thu, "\"Thu\""),
341
            (Fri, "\"Fri\""),
342
            (Sat, "\"Sat\""),
343
            (Sun, "\"Sun\""),
344
        ];
345
346
        for (weekday, expected_str) in cases {
347
            let string = to_string(&weekday).unwrap();
348
            assert_eq!(string, expected_str);
349
        }
350
    }
351
352
    #[test]
353
    #[cfg(feature = "serde")]
354
    fn test_serde_deserialize() {
355
        use serde_json::from_str;
356
        use Weekday::*;
357
358
        let cases: Vec<(&str, Weekday)> = vec![
359
            ("\"mon\"", Mon),
360
            ("\"MONDAY\"", Mon),
361
            ("\"MonDay\"", Mon),
362
            ("\"mOn\"", Mon),
363
            ("\"tue\"", Tue),
364
            ("\"tuesday\"", Tue),
365
            ("\"wed\"", Wed),
366
            ("\"wednesday\"", Wed),
367
            ("\"thu\"", Thu),
368
            ("\"thursday\"", Thu),
369
            ("\"fri\"", Fri),
370
            ("\"friday\"", Fri),
371
            ("\"sat\"", Sat),
372
            ("\"saturday\"", Sat),
373
            ("\"sun\"", Sun),
374
            ("\"sunday\"", Sun),
375
        ];
376
377
        for (str, expected_weekday) in cases {
378
            let weekday = from_str::<Weekday>(str).unwrap();
379
            assert_eq!(weekday, expected_weekday);
380
        }
381
382
        let errors: Vec<&str> =
383
            vec!["\"not a weekday\"", "\"monDAYs\"", "\"mond\"", "mon", "\"thur\"", "\"thurs\""];
384
385
        for str in errors {
386
            from_str::<Weekday>(str).unwrap_err();
387
        }
388
    }
389
390
    #[test]
391
    #[cfg(feature = "rkyv-validation")]
392
    fn test_rkyv_validation() {
393
        let mon = Weekday::Mon;
394
        let bytes = rkyv::to_bytes::<_, 1>(&mon).unwrap();
395
396
        assert_eq!(rkyv::from_bytes::<Weekday>(&bytes).unwrap(), mon);
397
    }
398
}