opening_hours_syntax/rules/
time.rs

1use std::cmp::Ordering;
2use std::fmt::Display;
3use std::ops::Range;
4
5use chrono::Duration;
6
7use crate::display::write_selector;
8use crate::extended_time::ExtendedTime;
9
10// TimeSelector
11
12#[derive(Clone, Debug, Hash, PartialEq, Eq)]
13pub struct TimeSelector {
14    pub time: Vec<TimeSpan>,
15}
16
17impl TimeSelector {
18    /// Note that not all cases can be covered
19    pub(crate) fn is_00_24(&self) -> bool {
20        self.time.len() == 1
21            && self.time.first()
22                == Some(&TimeSpan::fixed_range(
23                    ExtendedTime::MIDNIGHT_00,
24                    ExtendedTime::MIDNIGHT_24,
25                ))
26    }
27}
28
29impl TimeSelector {
30    #[inline]
31    pub fn new(time: Vec<TimeSpan>) -> Self {
32        if time.is_empty() {
33            Self::default()
34        } else {
35            Self { time }
36        }
37    }
38}
39
40impl Default for TimeSelector {
41    #[inline]
42    fn default() -> Self {
43        Self {
44            time: vec![TimeSpan::fixed_range(
45                ExtendedTime::MIDNIGHT_00,
46                ExtendedTime::MIDNIGHT_24,
47            )],
48        }
49    }
50}
51
52impl Display for TimeSelector {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        write_selector(f, &self.time)
55    }
56}
57
58// TimeSpan
59
60#[derive(Clone, Debug, Hash, PartialEq, Eq)]
61pub struct TimeSpan {
62    pub range: Range<Time>,
63    pub open_end: bool,
64    pub repeats: Option<Duration>,
65}
66
67impl TimeSpan {
68    #[inline]
69    pub const fn fixed_range(start: ExtendedTime, end: ExtendedTime) -> Self {
70        Self {
71            range: Time::Fixed(start)..Time::Fixed(end),
72            open_end: false,
73            repeats: None,
74        }
75    }
76}
77
78impl Display for TimeSpan {
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        write!(f, "{}", self.range.start)?;
81
82        if !self.open_end || self.range.end != Time::Fixed(ExtendedTime::MIDNIGHT_24) {
83            write!(f, "-{}", self.range.end)?;
84        }
85
86        if self.open_end {
87            write!(f, "+")?;
88        }
89
90        if let Some(repeat) = self.repeats {
91            if repeat.num_hours() > 0 {
92                write!(f, "{:02}:", repeat.num_hours())?;
93            }
94
95            write!(f, "{:02}", repeat.num_minutes() % 60)?;
96        }
97
98        Ok(())
99    }
100}
101
102// Time
103
104#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
105pub enum Time {
106    Fixed(ExtendedTime),
107    Variable(VariableTime),
108}
109
110impl Display for Time {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        match self {
113            Self::Fixed(time) => write!(f, "{time}"),
114            Self::Variable(time) => write!(f, "{time}"),
115        }
116    }
117}
118
119// VariableTime
120
121#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
122pub struct VariableTime {
123    pub event: TimeEvent,
124    pub offset: i16,
125}
126
127impl Display for VariableTime {
128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129        write!(f, "{}", self.event)?;
130
131        match self.offset.cmp(&0) {
132            Ordering::Less => write!(f, "{}", self.offset),
133            Ordering::Greater => write!(f, "+{}", self.offset),
134            Ordering::Equal => Ok(()),
135        }
136    }
137}
138
139// TimeEvent
140
141#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
142pub enum TimeEvent {
143    Dawn,
144    Sunrise,
145    Sunset,
146    Dusk,
147}
148
149impl TimeEvent {
150    pub const fn as_str(&self) -> &'static str {
151        match self {
152            Self::Dawn => "dawn",
153            Self::Sunrise => "sunrise",
154            Self::Sunset => "sunset",
155            Self::Dusk => "dusk",
156        }
157    }
158}
159
160impl Display for TimeEvent {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        write!(f, "{}", self.as_str())
163    }
164}