1use core::cmp::Ordering;
2
3use chrono::prelude::*;
4
5use super::constants::*;
6
7#[derive(Debug)]
8struct TimeDiffResult {
9 pub(crate) hours: i32,
10 pub(crate) minutes: i32,
11 pub(crate) seconds: i32,
12 pub(crate) nanoseconds: i32,
13}
14
15#[derive(Debug, Default, Clone, Eq, PartialEq)]
17pub struct DateDiffResult {
18 pub years: i32,
19 pub months: i32,
20 pub days: i32,
21}
22
23impl DateDiffResult {
24 #[doc(hidden)]
25 #[inline]
26 pub fn into_neg(mut self) -> Self {
27 self.years *= -1;
28 self.months *= -1;
29 self.days *= -1;
30
31 self
32 }
33}
34
35#[derive(Debug)]
36struct _DateDiffResult {
37 pub(crate) earlier_nanoseconds_of_day: u64,
38 pub(crate) later_nanoseconds_of_day: u64,
39 pub(crate) result: DateDiffResult,
40}
41
42#[derive(Debug, Default, Clone, Eq, PartialEq)]
44pub struct DateTimeDiffResult {
45 pub years: i32,
46 pub months: i32,
47 pub days: i32,
48 pub hours: i32,
49 pub minutes: i32,
50 pub seconds: i32,
51 pub nanoseconds: i32,
52}
53
54impl DateTimeDiffResult {
55 #[doc(hidden)]
56 #[inline]
57 pub fn into_neg(mut self) -> Self {
58 self.years *= -1;
59 self.months *= -1;
60 self.days *= -1;
61 self.hours *= -1;
62 self.minutes *= -1;
63 self.seconds *= -1;
64 self.nanoseconds *= -1;
65
66 self
67 }
68}
69
70impl From<DateDiffResult> for DateTimeDiffResult {
71 #[inline]
72 fn from(value: DateDiffResult) -> Self {
73 DateTimeDiffResult {
74 years: value.years,
75 months: value.months,
76 days: value.days,
77 ..DateTimeDiffResult::default()
78 }
79 }
80}
81
82impl From<DateTimeDiffResult> for DateDiffResult {
83 #[inline]
84 fn from(value: DateTimeDiffResult) -> Self {
85 DateDiffResult {
86 years: value.years, months: value.months, days: value.days
87 }
88 }
89}
90
91pub trait DateTimeDiff {
93 #[inline]
94 fn years(&self) -> i32 {
95 0
96 }
97
98 #[inline]
99 fn months(&self) -> i32 {
100 0
101 }
102
103 #[inline]
104 fn days(&self) -> i32 {
105 0
106 }
107
108 #[inline]
109 fn hours(&self) -> i32 {
110 0
111 }
112
113 #[inline]
114 fn minutes(&self) -> i32 {
115 0
116 }
117
118 #[inline]
119 fn seconds(&self) -> i32 {
120 0
121 }
122
123 #[inline]
124 fn nanoseconds(&self) -> i32 {
125 0
126 }
127}
128
129impl DateTimeDiff for DateDiffResult {
130 #[inline]
131 fn years(&self) -> i32 {
132 self.years
133 }
134
135 #[inline]
136 fn months(&self) -> i32 {
137 self.months
138 }
139
140 #[inline]
141 fn days(&self) -> i32 {
142 self.days
143 }
144}
145
146impl DateTimeDiff for DateTimeDiffResult {
147 #[inline]
148 fn years(&self) -> i32 {
149 self.years
150 }
151
152 #[inline]
153 fn months(&self) -> i32 {
154 self.months
155 }
156
157 #[inline]
158 fn days(&self) -> i32 {
159 self.days
160 }
161
162 #[inline]
163 fn hours(&self) -> i32 {
164 self.hours
165 }
166
167 #[inline]
168 fn minutes(&self) -> i32 {
169 self.minutes
170 }
171
172 #[inline]
173 fn seconds(&self) -> i32 {
174 self.seconds
175 }
176
177 #[inline]
178 fn nanoseconds(&self) -> i32 {
179 self.nanoseconds
180 }
181}
182
183#[inline]
184const fn _nanoseconds_to_units(mut nanoseconds: u64) -> TimeDiffResult {
185 let h = nanoseconds / HOUR_NANOSECONDS;
186 nanoseconds -= h * HOUR_NANOSECONDS;
187
188 let m = nanoseconds / MINUTE_NANOSECONDS;
189 nanoseconds -= m * MINUTE_NANOSECONDS;
190
191 let s = nanoseconds / SECOND_NANOSECONDS;
192 nanoseconds -= s * SECOND_NANOSECONDS;
193
194 TimeDiffResult {
195 hours: h as i32,
196 minutes: m as i32,
197 seconds: s as i32,
198 nanoseconds: nanoseconds as i32,
199 }
200}
201
202#[inline]
203const fn _time_diff(
204 earlier_nanoseconds_of_day: u64,
205 later_nanoseconds_of_day: u64,
206) -> TimeDiffResult {
207 let nanoseconds = if later_nanoseconds_of_day >= earlier_nanoseconds_of_day {
208 later_nanoseconds_of_day - earlier_nanoseconds_of_day
209 } else {
210 DAY_NANOSECONDS + later_nanoseconds_of_day - earlier_nanoseconds_of_day
211 };
212
213 _nanoseconds_to_units(nanoseconds)
214}
215
216#[inline]
217fn _date_time_nanoseconds_of_day(date_time: impl Timelike) -> u64 {
218 (date_time.hour() as u64 * HOUR_NANOSECONDS)
219 + (date_time.minute() as u64 * MINUTE_NANOSECONDS)
220 + (date_time.second() as u64 * SECOND_NANOSECONDS)
221 + date_time.nanosecond() as u64
222}
223
224#[inline]
225const fn _time_nanoseconds_of_day(timestamp: i64) -> u64 {
226 if timestamp >= 0 {
227 (timestamp as u64) % DAY_NANOSECONDS
228 } else {
229 let mut t = DAY_NANOSECONDS + ((-timestamp) as u64 % DAY_NANOSECONDS);
230
231 if t == DAY_NANOSECONDS {
232 t = 0;
233 }
234
235 t
236 }
237}
238
239fn _date_diff(
240 earlier: impl Datelike + Timelike,
241 later: impl Datelike + Timelike,
242 start_from_later: bool,
243) -> _DateDiffResult {
244 let mut earlier_year = earlier.year();
245 let mut earlier_month = earlier.month() as u8;
246 let mut earlier_date = earlier.day() as u8;
247
248 let mut later_year = later.year();
249 let mut later_month = later.month() as u8;
250 let mut later_date = later.day() as u8;
251
252 let later_nanoseconds_of_day = _date_time_nanoseconds_of_day(later);
253 let earlier_nanoseconds_of_day = _date_time_nanoseconds_of_day(earlier);
254
255 let years: i32;
256 let months: i32;
257 let days: i32;
258
259 if later_nanoseconds_of_day < earlier_nanoseconds_of_day {
260 if start_from_later {
263 if earlier_date < year_helper::get_days_in_month(earlier_year, earlier_month).unwrap() {
266 earlier_date += 1;
269 } else if earlier_month < 12 {
270 earlier_month += 1;
273 earlier_date = 1;
274 } else {
275 earlier_year += 1;
278 earlier_month = 1;
279 earlier_date = 1;
280 }
281 } else {
282 if later_date > 1 {
285 later_date -= 1;
288 } else if later_month > 1 {
289 later_month -= 1;
292 later_date = year_helper::get_days_in_month(later_year, later_month).unwrap();
293 } else {
294 later_year -= 1;
297 later_month = 12;
298 later_date = 31;
299 }
300 }
301 }
302
303 let year_diff = later_year - earlier_year;
304 let month_diff = later_month as i32 - earlier_month as i32;
305
306 match month_diff.cmp(&0) {
307 Ordering::Greater => {
308 years = year_diff;
311
312 if later_date >= earlier_date {
313 months = month_diff;
316 } else {
317 months = month_diff - 1;
320 }
321 },
322 Ordering::Less => {
323 years = year_diff - 1;
326
327 if later_date >= earlier_date {
328 months = month_diff + 12;
331 } else {
332 months = month_diff + 11;
335 }
336 },
337 Ordering::Equal => {
338 if later_date >= earlier_date {
341 years = year_diff;
344 months = 0;
345 } else {
346 years = year_diff - 1;
349 months = 11;
350 }
351 },
352 }
353
354 if later_date >= earlier_date {
355 if start_from_later {
358 days = later_date
359 .min(year_helper::get_days_in_month(earlier_year, earlier_month).unwrap())
360 as i32
361 - earlier_date as i32;
362 } else {
363 days = later_date as i32 - earlier_date as i32;
364 }
365 } else {
366 if start_from_later {
369 if earlier_month < 12 {
370 later_date = later_date
371 .min(year_helper::get_days_in_month(earlier_year, earlier_month + 1).unwrap())
372 } else {
373 }
375
376 days = (later_date
377 + (year_helper::get_days_in_month(earlier_year, earlier_month).unwrap()
378 - earlier_date)) as i32;
379 } else {
380 let days_in_month = if later_month > 1 {
381 year_helper::get_days_in_month(later_year, later_month - 1).unwrap()
382 } else {
383 31 };
385
386 if days_in_month > earlier_date {
387 days = (later_date + (days_in_month - earlier_date)) as i32;
388 } else {
389 days = later_date as i32;
390 }
391 }
392 }
393
394 _DateDiffResult {
395 earlier_nanoseconds_of_day,
396 later_nanoseconds_of_day,
397 result: DateDiffResult {
398 years,
399 months,
400 days,
401 },
402 }
403}
404
405#[inline]
427pub fn date_diff<DT: Datelike + Timelike + Ord>(from: DT, to: DT) -> DateDiffResult {
428 match to.cmp(&from) {
429 Ordering::Greater => _date_diff(from, to, false).result,
430 Ordering::Less => _date_diff(to, from, true).result.into_neg(),
431 Ordering::Equal => DateDiffResult::default(),
432 }
433}
434
435#[inline]
458pub fn date_time_diff<DT: Datelike + Timelike + Ord>(from: DT, to: DT) -> DateTimeDiffResult {
459 match to.cmp(&from) {
460 Ordering::Greater => {
461 let date_diff = _date_diff(from, to, false);
462
463 let time_diff = _time_diff(
464 date_diff.earlier_nanoseconds_of_day,
465 date_diff.later_nanoseconds_of_day,
466 );
467
468 let date_diff = date_diff.result;
469
470 DateTimeDiffResult {
471 years: date_diff.years,
472 months: date_diff.months,
473 days: date_diff.days,
474 hours: time_diff.hours,
475 minutes: time_diff.minutes,
476 seconds: time_diff.seconds,
477 nanoseconds: time_diff.nanoseconds,
478 }
479 },
480 Ordering::Less => {
481 let date_diff = _date_diff(to, from, true);
482
483 let time_diff = _time_diff(
484 date_diff.earlier_nanoseconds_of_day,
485 date_diff.later_nanoseconds_of_day,
486 );
487
488 let date_diff = date_diff.result;
489
490 DateTimeDiffResult {
491 years: -date_diff.years,
492 months: -date_diff.months,
493 days: -date_diff.days,
494 hours: -time_diff.hours,
495 minutes: -time_diff.minutes,
496 seconds: -time_diff.seconds,
497 nanoseconds: -time_diff.nanoseconds,
498 }
499 },
500 Ordering::Equal => DateTimeDiffResult::default(),
501 }
502}