Skip to main content

opening_hours_syntax/rules/
time.rs

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