1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
7#[repr(u8)]
8pub enum Weekday {
9 Sunday = 0,
11 Monday = 1,
13 Tuesday = 2,
15 Wednesday = 3,
17 Thursday = 4,
19 Friday = 5,
21 Saturday = 6,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
27#[repr(u8)]
28pub enum Meridiem {
29 AM = 0,
31 PM = 1,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37pub enum TimeUnit {
38 Year,
40 Quarter,
42 Month,
44 Week,
46 Day,
48 Hour,
50 Minute,
52 Second,
54 Millisecond,
56}
57
58#[derive(Debug, Clone, Default)]
60pub struct Duration {
61 pub year: Option<f64>,
63 pub quarter: Option<f64>,
65 pub month: Option<f64>,
67 pub week: Option<f64>,
69 pub day: Option<f64>,
71 pub hour: Option<f64>,
73 pub minute: Option<f64>,
75 pub second: Option<f64>,
77 pub millisecond: Option<f64>,
79}
80
81impl Duration {
82 pub const fn new() -> Self {
84 Self {
85 year: None,
86 quarter: None,
87 month: None,
88 week: None,
89 day: None,
90 hour: None,
91 minute: None,
92 second: None,
93 millisecond: None,
94 }
95 }
96
97 pub fn has_time_component(&self) -> bool {
99 self.hour.is_some()
100 || self.minute.is_some()
101 || self.second.is_some()
102 || self.millisecond.is_some()
103 }
104
105 pub fn has_date_component(&self) -> bool {
107 self.year.is_some()
108 || self.quarter.is_some()
109 || self.month.is_some()
110 || self.week.is_some()
111 || self.day.is_some()
112 }
113
114 pub fn reversed(&self) -> Self {
116 Self {
117 year: self.year.map(|v| -v),
118 quarter: self.quarter.map(|v| -v),
119 month: self.month.map(|v| -v),
120 week: self.week.map(|v| -v),
121 day: self.day.map(|v| -v),
122 hour: self.hour.map(|v| -v),
123 minute: self.minute.map(|v| -v),
124 second: self.second.map(|v| -v),
125 millisecond: self.millisecond.map(|v| -v),
126 }
127 }
128}
129
130pub fn add_duration(
132 mut date: chrono::DateTime<chrono::Local>,
133 duration: &Duration,
134) -> chrono::DateTime<chrono::Local> {
135 use chrono::{Datelike, Duration as ChronoDuration};
136
137 if let Some(years) = duration.year {
139 let y = years.floor() as i32;
140 if let Some(new_date) = date.with_year(date.year() + y) {
141 date = new_date;
142 }
143 }
144
145 if let Some(quarters) = duration.quarter {
147 let months = (quarters * 3.0).floor() as i32;
148 date = add_months(date, months);
149 }
150
151 if let Some(months) = duration.month {
153 let m = months.floor() as i32;
154 date = add_months(date, m);
155 }
156
157 if let Some(weeks) = duration.week {
159 let days = (weeks * 7.0).floor() as i64;
160 date += ChronoDuration::days(days);
161 }
162
163 if let Some(days) = duration.day {
165 let d = days.floor() as i64;
166 date += ChronoDuration::days(d);
167 }
168
169 if let Some(hours) = duration.hour {
171 let h = hours.floor() as i64;
172 date += ChronoDuration::hours(h);
173 }
174
175 if let Some(minutes) = duration.minute {
177 let m = minutes.floor() as i64;
178 date += ChronoDuration::minutes(m);
179 }
180
181 if let Some(seconds) = duration.second {
183 let s = seconds.floor() as i64;
184 date += ChronoDuration::seconds(s);
185 }
186
187 if let Some(ms) = duration.millisecond {
189 let m = ms.floor() as i64;
190 date += ChronoDuration::milliseconds(m);
191 }
192
193 date
194}
195
196fn add_months(
198 date: chrono::DateTime<chrono::Local>,
199 months: i32,
200) -> chrono::DateTime<chrono::Local> {
201 use chrono::Datelike;
202
203 let current_month = date.month() as i32;
204 let new_month = current_month + months;
205
206 if new_month <= 0 {
207 let years_back = (-new_month) / 12 + 1;
208 let final_month = 12 - ((-new_month) % 12);
209 let new_date = date.with_year(date.year() - years_back).unwrap_or(date);
210 new_date.with_month(final_month as u32).unwrap_or(new_date)
211 } else if new_month > 12 {
212 let years_forward = (new_month - 1) / 12;
213 let final_month = ((new_month - 1) % 12) + 1;
214 let new_date = date.with_year(date.year() + years_forward).unwrap_or(date);
215 new_date.with_month(final_month as u32).unwrap_or(new_date)
216 } else {
217 date.with_month(new_month as u32).unwrap_or(date)
218 }
219}