pace_time/
time_frame.rs

1use displaydoc::Display;
2use serde_derive::{Deserialize, Serialize};
3use tracing::debug;
4
5use crate::{
6    date::PaceDate,
7    date_time::PaceDateTime,
8    error::PaceTimeErrorKind,
9    flags::{DateFlags, TimeFlags},
10    time_range::TimeRangeOptions,
11    time_zone::PaceTimeZoneKind,
12};
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize, Display)]
15pub enum PaceTimeFrame {
16    /// Current Month
17    CurrentMonth,
18
19    /// Current Week
20    CurrentWeek,
21
22    /// Current Year
23    CurrentYear,
24
25    /// Date Range: {0}
26    DateRange(TimeRangeOptions),
27
28    /// Specific Date: {0}
29    SpecificDate(PaceDate),
30
31    /// Last Month
32    LastMonth,
33
34    /// Last Week
35    LastWeek,
36
37    /// Last Year
38    LastYear,
39
40    /// Today
41    #[default]
42    Today,
43
44    /// Yesterday
45    Yesterday,
46}
47
48impl
49    TryFrom<(
50        Option<&TimeFlags>,
51        Option<&DateFlags>,
52        PaceTimeZoneKind,
53        PaceTimeZoneKind,
54    )> for PaceTimeFrame
55{
56    type Error = PaceTimeErrorKind;
57
58    fn try_from(
59        (time_flags, date_flags, tz, tz_config): (
60            Option<&TimeFlags>,
61            Option<&DateFlags>,
62            PaceTimeZoneKind,
63            PaceTimeZoneKind,
64        ),
65    ) -> Result<Self, Self::Error> {
66        time_frame_from_date_and_time_flags_with_time_zone_kind(
67            time_flags, date_flags, tz, tz_config,
68        )
69    }
70}
71
72impl TryFrom<(Option<&TimeFlags>, Option<&DateFlags>, PaceTimeZoneKind)> for PaceTimeFrame {
73    type Error = PaceTimeErrorKind;
74
75    fn try_from(
76        (time_flags, date_flags, tz): (Option<&TimeFlags>, Option<&DateFlags>, PaceTimeZoneKind),
77    ) -> Result<Self, Self::Error> {
78        time_frame_from_date_and_time_flags_with_time_zone_kind(
79            time_flags,
80            date_flags,
81            tz,
82            PaceTimeZoneKind::NotSet,
83        )
84    }
85}
86
87impl TryFrom<(&DateFlags, PaceTimeZoneKind)> for PaceTimeFrame {
88    type Error = PaceTimeErrorKind;
89
90    fn try_from((date_flags, tz): (&DateFlags, PaceTimeZoneKind)) -> Result<Self, Self::Error> {
91        time_frame_from_date_and_time_flags_with_time_zone_kind(
92            None,
93            Some(date_flags),
94            tz,
95            PaceTimeZoneKind::NotSet,
96        )
97    }
98}
99
100impl TryFrom<&DateFlags> for PaceTimeFrame {
101    type Error = PaceTimeErrorKind;
102
103    fn try_from(date_flags: &DateFlags) -> Result<Self, Self::Error> {
104        time_frame_from_date_and_time_flags_with_time_zone_kind(
105            None,
106            Some(date_flags),
107            PaceTimeZoneKind::NotSet,
108            PaceTimeZoneKind::NotSet,
109        )
110    }
111}
112
113impl TryFrom<(Option<&DateFlags>, PaceTimeZoneKind)> for PaceTimeFrame {
114    type Error = PaceTimeErrorKind;
115
116    fn try_from(
117        (date_flags, tz): (Option<&DateFlags>, PaceTimeZoneKind),
118    ) -> Result<Self, Self::Error> {
119        time_frame_from_date_and_time_flags_with_time_zone_kind(
120            None,
121            date_flags,
122            tz,
123            PaceTimeZoneKind::NotSet,
124        )
125    }
126}
127
128impl TryFrom<(Option<&TimeFlags>, PaceTimeZoneKind)> for PaceTimeFrame {
129    type Error = PaceTimeErrorKind;
130
131    fn try_from(
132        (time_flags, tz): (Option<&TimeFlags>, PaceTimeZoneKind),
133    ) -> Result<Self, Self::Error> {
134        time_frame_from_date_and_time_flags_with_time_zone_kind(
135            time_flags,
136            None,
137            tz,
138            PaceTimeZoneKind::NotSet,
139        )
140    }
141}
142
143impl TryFrom<(&TimeFlags, PaceTimeZoneKind)> for PaceTimeFrame {
144    type Error = PaceTimeErrorKind;
145
146    fn try_from((time_flags, tz): (&TimeFlags, PaceTimeZoneKind)) -> Result<Self, Self::Error> {
147        time_frame_from_date_and_time_flags_with_time_zone_kind(
148            Some(time_flags),
149            None,
150            tz,
151            PaceTimeZoneKind::NotSet,
152        )
153    }
154}
155
156impl TryFrom<&TimeFlags> for PaceTimeFrame {
157    type Error = PaceTimeErrorKind;
158
159    fn try_from(time_flags: &TimeFlags) -> Result<Self, Self::Error> {
160        time_frame_from_date_and_time_flags_with_time_zone_kind(
161            Some(time_flags),
162            None,
163            PaceTimeZoneKind::NotSet,
164            PaceTimeZoneKind::NotSet,
165        )
166    }
167}
168
169impl TryFrom<PaceTimeZoneKind> for PaceTimeFrame {
170    type Error = PaceTimeErrorKind;
171
172    fn try_from(tz: PaceTimeZoneKind) -> Result<Self, Self::Error> {
173        time_frame_from_date_and_time_flags_with_time_zone_kind(
174            Some(&TimeFlags::default()),
175            None,
176            tz,
177            PaceTimeZoneKind::NotSet,
178        )
179    }
180}
181
182/// Get the time zone aware time frame from the time and date flags
183///
184/// # Arguments
185///
186/// * `time_flags` - The time flags
187/// * `date_flags` - The date flags
188/// * `tz_user` - The time zone kind from the user
189/// * `tz_config` - The time zone kind from the configuration
190///
191/// # Errors
192///
193/// Returns an error if the time frame could not be created
194///
195/// # Returns
196///
197/// Returns the time frame
198pub(crate) fn time_frame_from_date_and_time_flags_with_time_zone_kind(
199    time_flags: Option<&TimeFlags>,
200    date_flags: Option<&DateFlags>,
201    tz: PaceTimeZoneKind,
202    tz_config: PaceTimeZoneKind,
203) -> Result<PaceTimeFrame, PaceTimeErrorKind> {
204    let time_zone = match (tz, tz_config) {
205        (tzk, _) | (PaceTimeZoneKind::NotSet, tzk) if !tzk.is_not_set() => tzk,
206        _ => PaceTimeZoneKind::default(),
207    };
208
209    debug!("Using Time zone: {time_zone:?}");
210
211    let time_frame = match (time_flags, date_flags) {
212        (Some(TimeFlags::Today), _) => PaceTimeFrame::Today,
213        (Some(TimeFlags::Yesterday), _) => PaceTimeFrame::Yesterday,
214        (Some(TimeFlags::CurrentWeek), _) => PaceTimeFrame::CurrentWeek,
215        (Some(TimeFlags::LastWeek), _) => PaceTimeFrame::LastWeek,
216        (Some(TimeFlags::CurrentMonth), _) => PaceTimeFrame::CurrentMonth,
217        (Some(TimeFlags::LastMonth), _) => PaceTimeFrame::LastMonth,
218        (
219            None,
220            Some(DateFlags {
221                date: Some(specific_date),
222                from: None,
223                to: None,
224            }),
225        ) => {
226            // We have a specific date, but no date range
227            PaceTimeFrame::SpecificDate(PaceDate::from(specific_date.to_owned()))
228        }
229        (
230            None,
231            Some(DateFlags {
232                date: None,
233                from: Some(from),
234                to: None,
235            }),
236        ) => {
237            // We have a from date, but no end date
238            PaceTimeFrame::DateRange(
239                TimeRangeOptions::builder()
240                    .start(PaceDateTime::try_from((from.to_owned(), time_zone))?.start_of_day()?)
241                    .build(),
242            )
243        }
244        (
245            None,
246            Some(DateFlags {
247                date: None,
248                from: None,
249                to: Some(to),
250            }),
251        ) => {
252            // We have an end date, but no start date
253            PaceTimeFrame::DateRange(
254                TimeRangeOptions::builder()
255                    .end(PaceDateTime::try_from((to.to_owned(), time_zone))?.end_of_day()?)
256                    .build(),
257            )
258        }
259        (
260            None,
261            Some(DateFlags {
262                date: None,
263                from: Some(from),
264                to: Some(to),
265            }),
266        ) => {
267            // We have a date range
268            PaceTimeFrame::DateRange(
269                TimeRangeOptions::builder()
270                    .start(PaceDateTime::try_from((from.to_owned(), time_zone))?.start_of_day()?)
271                    .end(PaceDateTime::try_from((to.to_owned(), time_zone))?.end_of_day()?)
272                    .build(),
273            )
274        }
275        _ => PaceTimeFrame::default(),
276    };
277
278    debug!("Converted Time frame: {:?}", time_frame);
279
280    Ok(time_frame)
281}
282
283#[cfg(test)]
284mod tests {
285
286    use crate::flags::TimeFlags;
287
288    use super::*;
289
290    use eyre::Result;
291
292    #[test]
293    fn test_get_time_frame_from_flags_today_passes() -> Result<()> {
294        let time_flags = TimeFlags::Today;
295
296        let result = PaceTimeFrame::try_from(&time_flags)?;
297
298        assert_eq!(result, PaceTimeFrame::Today);
299
300        Ok(())
301    }
302}