1#[cfg(feature = "chrono")]
2mod chrono_support;
3#[cfg(feature = "jiff")]
4mod jiff_support;
5#[cfg(feature = "time")]
6mod time_support;
7
8use core::cmp::Ordering;
9
10use super::constants::*;
11
12#[derive(Debug)]
13struct TimeDiffResult {
14 pub(crate) hours: i32,
15 pub(crate) minutes: i32,
16 pub(crate) seconds: i32,
17 pub(crate) nanoseconds: i32,
18}
19
20#[derive(Debug, Default, Clone, Eq, PartialEq)]
22pub struct DateDiffResult {
23 pub years: i32,
24 pub months: i32,
25 pub days: i32,
26}
27
28impl DateDiffResult {
29 #[doc(hidden)]
30 #[inline]
31 pub fn into_neg(mut self) -> Self {
32 self.years *= -1;
33 self.months *= -1;
34 self.days *= -1;
35
36 self
37 }
38}
39
40#[derive(Debug)]
41struct _DateDiffResult {
42 pub(crate) earlier_nanoseconds_of_day: u64,
43 pub(crate) later_nanoseconds_of_day: u64,
44 pub(crate) result: DateDiffResult,
45}
46
47#[derive(Debug, Default, Clone, Eq, PartialEq)]
49pub struct DateTimeDiffResult {
50 pub years: i32,
51 pub months: i32,
52 pub days: i32,
53 pub hours: i32,
54 pub minutes: i32,
55 pub seconds: i32,
56 pub nanoseconds: i32,
57}
58
59impl DateTimeDiffResult {
60 #[doc(hidden)]
61 #[inline]
62 pub fn into_neg(mut self) -> Self {
63 self.years *= -1;
64 self.months *= -1;
65 self.days *= -1;
66 self.hours *= -1;
67 self.minutes *= -1;
68 self.seconds *= -1;
69 self.nanoseconds *= -1;
70
71 self
72 }
73}
74
75impl From<DateDiffResult> for DateTimeDiffResult {
76 #[inline]
77 fn from(value: DateDiffResult) -> Self {
78 DateTimeDiffResult {
79 years: value.years,
80 months: value.months,
81 days: value.days,
82 ..DateTimeDiffResult::default()
83 }
84 }
85}
86
87impl From<DateTimeDiffResult> for DateDiffResult {
88 #[inline]
89 fn from(value: DateTimeDiffResult) -> Self {
90 DateDiffResult {
91 years: value.years, months: value.months, days: value.days
92 }
93 }
94}
95
96pub trait DateTimeDiff {
98 #[inline]
99 fn years(&self) -> i32 {
100 0
101 }
102
103 #[inline]
104 fn months(&self) -> i32 {
105 0
106 }
107
108 #[inline]
109 fn days(&self) -> i32 {
110 0
111 }
112
113 #[inline]
114 fn hours(&self) -> i32 {
115 0
116 }
117
118 #[inline]
119 fn minutes(&self) -> i32 {
120 0
121 }
122
123 #[inline]
124 fn seconds(&self) -> i32 {
125 0
126 }
127
128 #[inline]
129 fn nanoseconds(&self) -> i32 {
130 0
131 }
132}
133
134pub trait DateTimeParts: Ord {
136 fn year(&self) -> i32;
137
138 fn month(&self) -> u8;
139
140 fn day(&self) -> u8;
141
142 fn hour(&self) -> u8;
143
144 fn minute(&self) -> u8;
145
146 fn second(&self) -> u8;
147
148 fn nanosecond(&self) -> u32;
149}
150
151impl DateTimeDiff for DateDiffResult {
152 #[inline]
153 fn years(&self) -> i32 {
154 self.years
155 }
156
157 #[inline]
158 fn months(&self) -> i32 {
159 self.months
160 }
161
162 #[inline]
163 fn days(&self) -> i32 {
164 self.days
165 }
166}
167
168impl DateTimeDiff for DateTimeDiffResult {
169 #[inline]
170 fn years(&self) -> i32 {
171 self.years
172 }
173
174 #[inline]
175 fn months(&self) -> i32 {
176 self.months
177 }
178
179 #[inline]
180 fn days(&self) -> i32 {
181 self.days
182 }
183
184 #[inline]
185 fn hours(&self) -> i32 {
186 self.hours
187 }
188
189 #[inline]
190 fn minutes(&self) -> i32 {
191 self.minutes
192 }
193
194 #[inline]
195 fn seconds(&self) -> i32 {
196 self.seconds
197 }
198
199 #[inline]
200 fn nanoseconds(&self) -> i32 {
201 self.nanoseconds
202 }
203}
204
205#[inline]
206const fn _nanoseconds_to_units(mut nanoseconds: u64) -> TimeDiffResult {
207 let h = nanoseconds / HOUR_NANOSECONDS;
208 nanoseconds -= h * HOUR_NANOSECONDS;
209
210 let m = nanoseconds / MINUTE_NANOSECONDS;
211 nanoseconds -= m * MINUTE_NANOSECONDS;
212
213 let s = nanoseconds / SECOND_NANOSECONDS;
214 nanoseconds -= s * SECOND_NANOSECONDS;
215
216 TimeDiffResult {
217 hours: h as i32,
218 minutes: m as i32,
219 seconds: s as i32,
220 nanoseconds: nanoseconds as i32,
221 }
222}
223
224#[inline]
225const fn _time_diff(
226 earlier_nanoseconds_of_day: u64,
227 later_nanoseconds_of_day: u64,
228) -> TimeDiffResult {
229 let nanoseconds = if later_nanoseconds_of_day >= earlier_nanoseconds_of_day {
230 later_nanoseconds_of_day - earlier_nanoseconds_of_day
231 } else {
232 DAY_NANOSECONDS + later_nanoseconds_of_day - earlier_nanoseconds_of_day
233 };
234
235 _nanoseconds_to_units(nanoseconds)
236}
237
238#[inline]
239fn _date_time_nanoseconds_of_day(date_time: &impl DateTimeParts) -> u64 {
240 (date_time.hour() as u64 * HOUR_NANOSECONDS)
241 + (date_time.minute() as u64 * MINUTE_NANOSECONDS)
242 + (date_time.second() as u64 * SECOND_NANOSECONDS)
243 + date_time.nanosecond() as u64
244}
245
246fn _date_diff(
247 earlier: &impl DateTimeParts,
248 later: &impl DateTimeParts,
249 start_from_later: bool,
250) -> _DateDiffResult {
251 let mut earlier_year = earlier.year();
252 let mut earlier_month = earlier.month();
253 let mut earlier_date = earlier.day();
254
255 let mut later_year = later.year();
256 let mut later_month = later.month();
257 let mut later_date = later.day();
258
259 let later_nanoseconds_of_day = _date_time_nanoseconds_of_day(later);
260 let earlier_nanoseconds_of_day = _date_time_nanoseconds_of_day(earlier);
261
262 let years: i32;
263 let months: i32;
264 let days: i32;
265
266 if later_nanoseconds_of_day < earlier_nanoseconds_of_day {
267 if start_from_later {
270 if earlier_date < year_helper::get_days_in_month(earlier_year, earlier_month).unwrap() {
273 earlier_date += 1;
276 } else if earlier_month < 12 {
277 earlier_month += 1;
280 earlier_date = 1;
281 } else {
282 earlier_year += 1;
285 earlier_month = 1;
286 earlier_date = 1;
287 }
288 } else {
289 if later_date > 1 {
292 later_date -= 1;
295 } else if later_month > 1 {
296 later_month -= 1;
299 later_date = year_helper::get_days_in_month(later_year, later_month).unwrap();
300 } else {
301 later_year -= 1;
304 later_month = 12;
305 later_date = 31;
306 }
307 }
308 }
309
310 let year_diff = later_year - earlier_year;
311 let month_diff = later_month as i32 - earlier_month as i32;
312
313 match month_diff.cmp(&0) {
314 Ordering::Greater => {
315 years = year_diff;
318
319 if later_date >= earlier_date {
320 months = month_diff;
323 } else {
324 months = month_diff - 1;
327 }
328 },
329 Ordering::Less => {
330 years = year_diff - 1;
333
334 if later_date >= earlier_date {
335 months = month_diff + 12;
338 } else {
339 months = month_diff + 11;
342 }
343 },
344 Ordering::Equal => {
345 if later_date >= earlier_date {
348 years = year_diff;
351 months = 0;
352 } else {
353 years = year_diff - 1;
356 months = 11;
357 }
358 },
359 }
360
361 if later_date >= earlier_date {
362 if start_from_later {
365 days = later_date
366 .min(year_helper::get_days_in_month(earlier_year, earlier_month).unwrap())
367 as i32
368 - earlier_date as i32;
369 } else {
370 days = later_date as i32 - earlier_date as i32;
371 }
372 } else {
373 if start_from_later {
376 if earlier_month < 12 {
377 later_date = later_date
378 .min(year_helper::get_days_in_month(earlier_year, earlier_month + 1).unwrap())
379 } else {
380 }
382
383 days = (later_date
384 + (year_helper::get_days_in_month(earlier_year, earlier_month).unwrap()
385 - earlier_date)) as i32;
386 } else {
387 let days_in_month = if later_month > 1 {
388 year_helper::get_days_in_month(later_year, later_month - 1).unwrap()
389 } else {
390 31 };
392
393 if days_in_month > earlier_date {
394 days = (later_date + (days_in_month - earlier_date)) as i32;
395 } else {
396 days = later_date as i32;
397 }
398 }
399 }
400
401 _DateDiffResult {
402 earlier_nanoseconds_of_day,
403 later_nanoseconds_of_day,
404 result: DateDiffResult {
405 years,
406 months,
407 days,
408 },
409 }
410}
411
412#[inline]
437pub fn date_diff<DT: DateTimeParts>(from: DT, to: DT) -> DateDiffResult {
438 match to.cmp(&from) {
439 Ordering::Greater => _date_diff(&from, &to, false).result,
440 Ordering::Less => _date_diff(&to, &from, true).result.into_neg(),
441 Ordering::Equal => DateDiffResult::default(),
442 }
443}
444
445#[inline]
471pub fn date_time_diff<DT: DateTimeParts>(from: DT, to: DT) -> DateTimeDiffResult {
472 match to.cmp(&from) {
473 Ordering::Greater => {
474 let date_diff = _date_diff(&from, &to, false);
475
476 let time_diff = _time_diff(
477 date_diff.earlier_nanoseconds_of_day,
478 date_diff.later_nanoseconds_of_day,
479 );
480
481 let date_diff = date_diff.result;
482
483 DateTimeDiffResult {
484 years: date_diff.years,
485 months: date_diff.months,
486 days: date_diff.days,
487 hours: time_diff.hours,
488 minutes: time_diff.minutes,
489 seconds: time_diff.seconds,
490 nanoseconds: time_diff.nanoseconds,
491 }
492 },
493 Ordering::Less => {
494 let date_diff = _date_diff(&to, &from, true);
495
496 let time_diff = _time_diff(
497 date_diff.earlier_nanoseconds_of_day,
498 date_diff.later_nanoseconds_of_day,
499 );
500
501 let date_diff = date_diff.result;
502
503 DateTimeDiffResult {
504 years: -date_diff.years,
505 months: -date_diff.months,
506 days: -date_diff.days,
507 hours: -time_diff.hours,
508 minutes: -time_diff.minutes,
509 seconds: -time_diff.seconds,
510 nanoseconds: -time_diff.nanoseconds,
511 }
512 },
513 Ordering::Equal => DateTimeDiffResult::default(),
514 }
515}