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
224fn _date_diff(
225 earlier: impl Datelike + Timelike,
226 later: impl Datelike + Timelike,
227 start_from_later: bool,
228) -> _DateDiffResult {
229 let mut earlier_year = earlier.year();
230 let mut earlier_month = earlier.month() as u8;
231 let mut earlier_date = earlier.day() as u8;
232
233 let mut later_year = later.year();
234 let mut later_month = later.month() as u8;
235 let mut later_date = later.day() as u8;
236
237 let later_nanoseconds_of_day = _date_time_nanoseconds_of_day(later);
238 let earlier_nanoseconds_of_day = _date_time_nanoseconds_of_day(earlier);
239
240 let years: i32;
241 let months: i32;
242 let days: i32;
243
244 if later_nanoseconds_of_day < earlier_nanoseconds_of_day {
245 if start_from_later {
248 if earlier_date < year_helper::get_days_in_month(earlier_year, earlier_month).unwrap() {
251 earlier_date += 1;
254 } else if earlier_month < 12 {
255 earlier_month += 1;
258 earlier_date = 1;
259 } else {
260 earlier_year += 1;
263 earlier_month = 1;
264 earlier_date = 1;
265 }
266 } else {
267 if later_date > 1 {
270 later_date -= 1;
273 } else if later_month > 1 {
274 later_month -= 1;
277 later_date = year_helper::get_days_in_month(later_year, later_month).unwrap();
278 } else {
279 later_year -= 1;
282 later_month = 12;
283 later_date = 31;
284 }
285 }
286 }
287
288 let year_diff = later_year - earlier_year;
289 let month_diff = later_month as i32 - earlier_month as i32;
290
291 match month_diff.cmp(&0) {
292 Ordering::Greater => {
293 years = year_diff;
296
297 if later_date >= earlier_date {
298 months = month_diff;
301 } else {
302 months = month_diff - 1;
305 }
306 },
307 Ordering::Less => {
308 years = year_diff - 1;
311
312 if later_date >= earlier_date {
313 months = month_diff + 12;
316 } else {
317 months = month_diff + 11;
320 }
321 },
322 Ordering::Equal => {
323 if later_date >= earlier_date {
326 years = year_diff;
329 months = 0;
330 } else {
331 years = year_diff - 1;
334 months = 11;
335 }
336 },
337 }
338
339 if later_date >= earlier_date {
340 if start_from_later {
343 days = later_date
344 .min(year_helper::get_days_in_month(earlier_year, earlier_month).unwrap())
345 as i32
346 - earlier_date as i32;
347 } else {
348 days = later_date as i32 - earlier_date as i32;
349 }
350 } else {
351 if start_from_later {
354 if earlier_month < 12 {
355 later_date = later_date
356 .min(year_helper::get_days_in_month(earlier_year, earlier_month + 1).unwrap())
357 } else {
358 }
360
361 days = (later_date
362 + (year_helper::get_days_in_month(earlier_year, earlier_month).unwrap()
363 - earlier_date)) as i32;
364 } else {
365 let days_in_month = if later_month > 1 {
366 year_helper::get_days_in_month(later_year, later_month - 1).unwrap()
367 } else {
368 31 };
370
371 if days_in_month > earlier_date {
372 days = (later_date + (days_in_month - earlier_date)) as i32;
373 } else {
374 days = later_date as i32;
375 }
376 }
377 }
378
379 _DateDiffResult {
380 earlier_nanoseconds_of_day,
381 later_nanoseconds_of_day,
382 result: DateDiffResult {
383 years,
384 months,
385 days,
386 },
387 }
388}
389
390#[inline]
412pub fn date_diff<DT: Datelike + Timelike + Ord>(from: DT, to: DT) -> DateDiffResult {
413 match to.cmp(&from) {
414 Ordering::Greater => _date_diff(from, to, false).result,
415 Ordering::Less => _date_diff(to, from, true).result.into_neg(),
416 Ordering::Equal => DateDiffResult::default(),
417 }
418}
419
420#[inline]
443pub fn date_time_diff<DT: Datelike + Timelike + Ord>(from: DT, to: DT) -> DateTimeDiffResult {
444 match to.cmp(&from) {
445 Ordering::Greater => {
446 let date_diff = _date_diff(from, to, false);
447
448 let time_diff = _time_diff(
449 date_diff.earlier_nanoseconds_of_day,
450 date_diff.later_nanoseconds_of_day,
451 );
452
453 let date_diff = date_diff.result;
454
455 DateTimeDiffResult {
456 years: date_diff.years,
457 months: date_diff.months,
458 days: date_diff.days,
459 hours: time_diff.hours,
460 minutes: time_diff.minutes,
461 seconds: time_diff.seconds,
462 nanoseconds: time_diff.nanoseconds,
463 }
464 },
465 Ordering::Less => {
466 let date_diff = _date_diff(to, from, true);
467
468 let time_diff = _time_diff(
469 date_diff.earlier_nanoseconds_of_day,
470 date_diff.later_nanoseconds_of_day,
471 );
472
473 let date_diff = date_diff.result;
474
475 DateTimeDiffResult {
476 years: -date_diff.years,
477 months: -date_diff.months,
478 days: -date_diff.days,
479 hours: -time_diff.hours,
480 minutes: -time_diff.minutes,
481 seconds: -time_diff.seconds,
482 nanoseconds: -time_diff.nanoseconds,
483 }
484 },
485 Ordering::Equal => DateTimeDiffResult::default(),
486 }
487}