chrono_node/calculation/
weekdays.rs1use crate::calculation::duration::{Duration, DurationUnit};
4use crate::core::components::{weekday, Component, ParsingComponents};
5use crate::core::js_date::JsDate;
6use crate::core::reference::ReferenceWithTimezone;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum WeekdayModifier {
11 This,
12 Next,
13 Last,
14}
15
16pub fn create_parsing_components_at_weekday(
18 reference: ReferenceWithTimezone,
19 weekday: i64,
20 modifier: Option<WeekdayModifier>,
21) -> ParsingComponents {
22 let ref_date = reference.get_date_with_adjusted_timezone();
23 let days_to_weekday = get_days_to_weekday(ref_date, weekday, modifier);
24
25 let mut components = ParsingComponents::new(reference, &[]);
26 components.add_duration_as_implied(&mut Duration::from_pairs(&[(
27 DurationUnit::Day,
28 days_to_weekday as f64,
29 )]));
30 components.assign(Component::Weekday, weekday);
31 components
32}
33
34pub fn get_days_to_weekday(ref_date: JsDate, weekday: i64, modifier: Option<WeekdayModifier>) -> i64 {
36 let ref_weekday = ref_date.get_day();
37 match modifier {
38 Some(WeekdayModifier::This) => get_days_forward_to_weekday(ref_date, weekday),
39 Some(WeekdayModifier::Last) => get_backward_days_to_weekday(ref_date, weekday),
40 Some(WeekdayModifier::Next) => {
41 if ref_weekday == weekday::SUNDAY {
43 return if weekday == weekday::SUNDAY { 7 } else { weekday };
44 }
45 if ref_weekday == weekday::SATURDAY {
47 if weekday == weekday::SATURDAY {
48 return 7;
49 }
50 if weekday == weekday::SUNDAY {
51 return 8;
52 }
53 return 1 + weekday;
54 }
55 if weekday < ref_weekday && weekday != weekday::SUNDAY {
58 get_days_forward_to_weekday(ref_date, weekday)
59 } else {
60 get_days_forward_to_weekday(ref_date, weekday) + 7
61 }
62 }
63 None => get_days_to_weekday_closest(ref_date, weekday),
64 }
65}
66
67pub fn get_days_to_weekday_closest(ref_date: JsDate, weekday: i64) -> i64 {
69 let backward = get_backward_days_to_weekday(ref_date, weekday);
70 let forward = get_days_forward_to_weekday(ref_date, weekday);
71 if forward < -backward {
72 forward
73 } else {
74 backward
75 }
76}
77
78pub fn get_days_forward_to_weekday(ref_date: JsDate, weekday: i64) -> i64 {
80 let mut forward = weekday - ref_date.get_day();
81 if forward < 0 {
82 forward += 7;
83 }
84 forward
85}
86
87pub fn get_backward_days_to_weekday(ref_date: JsDate, weekday: i64) -> i64 {
89 let mut backward = weekday - ref_date.get_day();
90 if backward >= 0 {
91 backward -= 7;
92 }
93 backward
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 fn thu() -> JsDate {
102 JsDate::parse_iso("2012-08-09T00:00:00.000Z").unwrap()
103 }
104
105 #[test]
106 fn closest_and_modifiers() {
107 assert_eq!(get_days_to_weekday(thu(), weekday::MONDAY, None), -3);
108 assert_eq!(get_days_to_weekday(thu(), weekday::SUNDAY, None), 3);
109 assert_eq!(get_days_to_weekday(thu(), weekday::THURSDAY, None), 0);
110 assert_eq!(
111 get_days_to_weekday(thu(), weekday::FRIDAY, Some(WeekdayModifier::Last)),
112 -6
113 );
114 assert_eq!(
115 get_days_to_weekday(thu(), weekday::FRIDAY, Some(WeekdayModifier::Next)),
116 8
117 );
118 assert_eq!(
119 get_days_to_weekday(thu(), weekday::MONDAY, Some(WeekdayModifier::Next)),
120 4
121 );
122 assert_eq!(
123 get_days_to_weekday(thu(), weekday::MONDAY, Some(WeekdayModifier::This)),
124 4
125 );
126 }
127}