Skip to main content

teaql_tool_std/
daterange.rs

1use chrono::{DateTime, Duration, Local, NaiveTime, Timelike};
2
3#[derive(Debug, Clone, PartialEq)]
4pub struct DateRange {
5    pub start: DateTime<Local>,
6    pub end: DateTime<Local>,
7}
8
9impl DateRange {
10    pub fn new(start: DateTime<Local>, end: DateTime<Local>) -> Self {
11        Self { start, end }
12    }
13}
14
15pub struct DateRangeTool;
16
17impl DateRangeTool {
18    pub fn new() -> Self {
19        Self
20    }
21
22    /// Helper to get the start of the day
23    fn begin_of_day(&self, dt: DateTime<Local>) -> DateTime<Local> {
24        dt.with_time(NaiveTime::from_hms_opt(0, 0, 0).unwrap()).unwrap()
25    }
26
27    /// Helper to get the end of the day
28    fn end_of_day(&self, dt: DateTime<Local>) -> DateTime<Local> {
29        dt.with_time(NaiveTime::from_hms_nano_opt(23, 59, 59, 999_999_999).unwrap()).unwrap()
30    }
31
32    pub fn today(&self) -> DateRange {
33        self.offset_day(0)
34    }
35
36    pub fn yesterday(&self) -> DateRange {
37        self.offset_day(-1)
38    }
39
40    pub fn tomorrow(&self) -> DateRange {
41        self.offset_day(1)
42    }
43
44    pub fn offset_day(&self, n: i64) -> DateRange {
45        let the_day = Local::now() + Duration::days(n);
46        DateRange::new(self.begin_of_day(the_day), self.end_of_day(the_day))
47    }
48
49    pub fn last_n_days(&self, n: i64) -> Option<DateRange> {
50        if n <= 0 {
51            return None;
52        }
53        let yesterday = Local::now() - Duration::days(1);
54        let start_day = yesterday - Duration::days(n - 1);
55        Some(DateRange::new(self.begin_of_day(start_day), self.end_of_day(yesterday)))
56    }
57
58    pub fn next_n_days(&self, n: i64) -> Option<DateRange> {
59        if n <= 0 {
60            return None;
61        }
62        let tomorrow = Local::now() + Duration::days(1);
63        let end_day = tomorrow + Duration::days(n - 1);
64        Some(DateRange::new(self.begin_of_day(tomorrow), self.end_of_day(end_day)))
65    }
66
67    /// Helper to get the start of the hour
68    fn begin_of_hour(&self, dt: DateTime<Local>) -> DateTime<Local> {
69        dt.with_time(NaiveTime::from_hms_opt(dt.time().hour(), 0, 0).unwrap()).unwrap()
70    }
71
72    /// Helper to get the end of the hour
73    fn end_of_hour(&self, dt: DateTime<Local>) -> DateTime<Local> {
74        dt.with_time(NaiveTime::from_hms_nano_opt(dt.time().hour(), 59, 59, 999_999_999).unwrap()).unwrap()
75    }
76
77    pub fn this_hour(&self) -> DateRange {
78        self.offset_hour(0)
79    }
80
81    pub fn last_hour(&self) -> DateRange {
82        self.offset_hour(-1)
83    }
84
85    pub fn next_hour(&self) -> DateRange {
86        self.offset_hour(1)
87    }
88
89    pub fn offset_hour(&self, n: i64) -> DateRange {
90        let the_hour = Local::now() + Duration::hours(n);
91        DateRange::new(self.begin_of_hour(the_hour), self.end_of_hour(the_hour))
92    }
93
94    pub fn last_n_hours(&self, n: i64) -> Option<DateRange> {
95        if n <= 0 {
96            return None;
97        }
98        let last_hr = Local::now() - Duration::hours(1);
99        let start_hr = last_hr - Duration::hours(n - 1);
100        Some(DateRange::new(self.begin_of_hour(start_hr), self.end_of_hour(last_hr)))
101    }
102
103    pub fn next_n_hours(&self, n: i64) -> Option<DateRange> {
104        if n <= 0 {
105            return None;
106        }
107        let next_hr = Local::now() + Duration::hours(1);
108        let end_hr = next_hr + Duration::hours(n - 1);
109        Some(DateRange::new(self.begin_of_hour(next_hr), self.end_of_hour(end_hr)))
110    }
111}
112
113impl Default for DateRangeTool {
114    fn default() -> Self {
115        Self::new()
116    }
117}