1use std::hash::Hash;
16
17use arrow::datatypes::IntervalUnit as ArrowIntervalUnit;
18use serde::{Deserialize, Serialize};
19
20#[derive(
21 Debug, Default, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
22)]
23pub enum IntervalUnit {
24 YearMonth,
26 DayTime,
29 #[default]
37 MonthDayNano,
38}
39
40impl From<&ArrowIntervalUnit> for IntervalUnit {
41 fn from(unit: &ArrowIntervalUnit) -> Self {
42 match unit {
43 ArrowIntervalUnit::YearMonth => IntervalUnit::YearMonth,
44 ArrowIntervalUnit::DayTime => IntervalUnit::DayTime,
45 ArrowIntervalUnit::MonthDayNano => IntervalUnit::MonthDayNano,
46 }
47 }
48}
49
50impl From<ArrowIntervalUnit> for IntervalUnit {
51 fn from(unit: ArrowIntervalUnit) -> Self {
52 (&unit).into()
53 }
54}
55
56#[derive(
58 Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize,
59)]
60#[repr(C)]
61pub struct IntervalYearMonth {
62 pub months: i32,
64}
65
66impl IntervalYearMonth {
67 pub fn new(months: i32) -> Self {
68 Self { months }
69 }
70
71 pub fn to_i32(&self) -> i32 {
72 self.months
73 }
74
75 pub fn from_i32(months: i32) -> Self {
76 Self { months }
77 }
78
79 pub fn negative(&self) -> Self {
80 Self::new(-self.months)
81 }
82
83 pub fn to_iso8601_string(&self) -> String {
84 IntervalFormat::from(*self).to_iso8601_string()
85 }
86}
87
88impl From<IntervalYearMonth> for IntervalFormat {
89 fn from(interval: IntervalYearMonth) -> Self {
90 IntervalFormat {
91 years: interval.months / 12,
92 months: interval.months % 12,
93 ..Default::default()
94 }
95 }
96}
97
98impl From<i32> for IntervalYearMonth {
99 fn from(v: i32) -> Self {
100 Self::from_i32(v)
101 }
102}
103
104impl From<IntervalYearMonth> for i32 {
105 fn from(v: IntervalYearMonth) -> Self {
106 v.to_i32()
107 }
108}
109
110impl From<IntervalYearMonth> for serde_json::Value {
111 fn from(v: IntervalYearMonth) -> Self {
112 serde_json::Value::from(v.to_i32())
113 }
114}
115
116#[derive(
117 Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize,
118)]
119#[repr(C)]
120pub struct IntervalDayTime {
121 pub days: i32,
123 pub milliseconds: i32,
125}
126
127impl IntervalDayTime {
128 pub const ZERO: Self = Self::new(0, 0);
130
131 pub const MINUS_ONE: Self = Self::new(-1, -1);
133
134 pub const MAX: Self = Self::new(i32::MAX, i32::MAX);
136
137 pub const MIN: Self = Self::new(i32::MIN, i32::MIN);
139
140 pub const fn new(days: i32, milliseconds: i32) -> Self {
141 Self { days, milliseconds }
142 }
143
144 pub fn to_i64(&self) -> i64 {
145 let d = (self.days as u64 & u32::MAX as u64) << 32;
146 let m = self.milliseconds as u64 & u32::MAX as u64;
147 (d | m) as i64
148 }
149
150 pub fn from_i64(value: i64) -> Self {
151 let days = (value >> 32) as i32;
152 let milliseconds = value as i32;
153 Self { days, milliseconds }
154 }
155
156 pub fn negative(&self) -> Self {
157 Self::new(-self.days, -self.milliseconds)
158 }
159
160 pub fn to_iso8601_string(&self) -> String {
161 IntervalFormat::from(*self).to_iso8601_string()
162 }
163
164 pub fn as_millis(&self) -> i64 {
165 self.days as i64 * MS_PER_DAY + self.milliseconds as i64
166 }
167}
168
169impl From<i64> for IntervalDayTime {
170 fn from(v: i64) -> Self {
171 Self::from_i64(v)
172 }
173}
174
175impl From<IntervalDayTime> for i64 {
176 fn from(v: IntervalDayTime) -> Self {
177 v.to_i64()
178 }
179}
180
181impl From<IntervalDayTime> for serde_json::Value {
182 fn from(v: IntervalDayTime) -> Self {
183 serde_json::Value::from(v.to_i64())
184 }
185}
186
187impl From<arrow::datatypes::IntervalDayTime> for IntervalDayTime {
188 fn from(value: arrow::datatypes::IntervalDayTime) -> Self {
189 Self {
190 days: value.days,
191 milliseconds: value.milliseconds,
192 }
193 }
194}
195
196impl From<IntervalDayTime> for arrow::datatypes::IntervalDayTime {
197 fn from(value: IntervalDayTime) -> Self {
198 Self {
199 days: value.days,
200 milliseconds: value.milliseconds,
201 }
202 }
203}
204
205pub const MS_PER_SEC: i64 = 1_000;
207pub const MS_PER_MINUTE: i64 = 60 * MS_PER_SEC;
208pub const MS_PER_HOUR: i64 = 60 * MS_PER_MINUTE;
209pub const MS_PER_DAY: i64 = 24 * MS_PER_HOUR;
210pub const NANOS_PER_MILLI: i64 = 1_000_000;
211
212impl From<IntervalDayTime> for IntervalFormat {
213 fn from(interval: IntervalDayTime) -> Self {
214 IntervalFormat {
215 days: interval.days,
216 hours: interval.milliseconds as i64 / MS_PER_HOUR,
217 minutes: (interval.milliseconds as i64 % MS_PER_HOUR) / MS_PER_MINUTE,
218 seconds: (interval.milliseconds as i64 % MS_PER_MINUTE) / MS_PER_SEC,
219 microseconds: (interval.milliseconds as i64 % MS_PER_SEC) * MS_PER_SEC,
220 ..Default::default()
221 }
222 }
223}
224
225#[derive(
226 Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize,
227)]
228#[repr(C)]
229pub struct IntervalMonthDayNano {
230 pub months: i32,
232 pub days: i32,
234 pub nanoseconds: i64,
236}
237
238impl IntervalMonthDayNano {
239 pub const ZERO: Self = Self::new(0, 0, 0);
241
242 pub const MINUS_ONE: Self = Self::new(-1, -1, -1);
244
245 pub const MAX: Self = Self::new(i32::MAX, i32::MAX, i64::MAX);
247
248 pub const MIN: Self = Self::new(i32::MIN, i32::MIN, i64::MIN);
250
251 pub const fn new(months: i32, days: i32, nanoseconds: i64) -> Self {
252 Self {
253 months,
254 days,
255 nanoseconds,
256 }
257 }
258
259 pub fn to_i128(&self) -> i128 {
260 let m = (self.months as u128 & u32::MAX as u128) << 96;
261 let d = (self.days as u128 & u32::MAX as u128) << 64;
262 let n = self.nanoseconds as u128 & u64::MAX as u128;
263 (m | d | n) as i128
264 }
265
266 pub fn from_i128(value: i128) -> Self {
267 let months = (value >> 96) as i32;
268 let days = (value >> 64) as i32;
269 let nanoseconds = value as i64;
270 Self {
271 months,
272 days,
273 nanoseconds,
274 }
275 }
276
277 pub fn negative(&self) -> Self {
278 Self::new(-self.months, -self.days, -self.nanoseconds)
279 }
280
281 pub fn to_iso8601_string(&self) -> String {
282 IntervalFormat::from(*self).to_iso8601_string()
283 }
284}
285
286impl From<i128> for IntervalMonthDayNano {
287 fn from(v: i128) -> Self {
288 Self::from_i128(v)
289 }
290}
291
292impl From<IntervalMonthDayNano> for i128 {
293 fn from(v: IntervalMonthDayNano) -> Self {
294 v.to_i128()
295 }
296}
297
298impl From<IntervalMonthDayNano> for serde_json::Value {
299 fn from(v: IntervalMonthDayNano) -> Self {
300 serde_json::Value::from(v.to_i128().to_string())
301 }
302}
303
304impl From<arrow::datatypes::IntervalMonthDayNano> for IntervalMonthDayNano {
305 fn from(value: arrow::datatypes::IntervalMonthDayNano) -> Self {
306 Self {
307 months: value.months,
308 days: value.days,
309 nanoseconds: value.nanoseconds,
310 }
311 }
312}
313
314impl From<IntervalMonthDayNano> for arrow::datatypes::IntervalMonthDayNano {
315 fn from(value: IntervalMonthDayNano) -> Self {
316 Self {
317 months: value.months,
318 days: value.days,
319 nanoseconds: value.nanoseconds,
320 }
321 }
322}
323
324pub const NS_PER_SEC: i64 = 1_000_000_000;
326pub const NS_PER_MINUTE: i64 = 60 * NS_PER_SEC;
327pub const NS_PER_HOUR: i64 = 60 * NS_PER_MINUTE;
328pub const NS_PER_DAY: i64 = 24 * NS_PER_HOUR;
329
330impl From<IntervalMonthDayNano> for IntervalFormat {
331 fn from(interval: IntervalMonthDayNano) -> Self {
332 IntervalFormat {
333 years: interval.months / 12,
334 months: interval.months % 12,
335 days: interval.days,
336 hours: interval.nanoseconds / NS_PER_HOUR,
337 minutes: (interval.nanoseconds % NS_PER_HOUR) / NS_PER_MINUTE,
338 seconds: (interval.nanoseconds % NS_PER_MINUTE) / NS_PER_SEC,
339 microseconds: (interval.nanoseconds % NS_PER_SEC) / 1_000,
340 }
341 }
342}
343
344pub fn interval_year_month_to_month_day_nano(interval: IntervalYearMonth) -> IntervalMonthDayNano {
345 IntervalMonthDayNano {
346 months: interval.months,
347 days: 0,
348 nanoseconds: 0,
349 }
350}
351
352pub fn interval_day_time_to_month_day_nano(interval: IntervalDayTime) -> IntervalMonthDayNano {
353 IntervalMonthDayNano {
354 months: 0,
355 days: interval.days,
356 nanoseconds: interval.milliseconds as i64 * NANOS_PER_MILLI,
357 }
358}
359
360#[derive(Debug, Clone, Default, Copy, Serialize, Deserialize)]
363pub struct IntervalFormat {
364 pub years: i32,
365 pub months: i32,
366 pub days: i32,
367 pub hours: i64,
368 pub minutes: i64,
369 pub seconds: i64,
370 pub microseconds: i64,
371}
372
373impl IntervalFormat {
374 pub fn is_zero(&self) -> bool {
376 self.years == 0
377 && self.months == 0
378 && self.days == 0
379 && self.hours == 0
380 && self.minutes == 0
381 && self.seconds == 0
382 && self.microseconds == 0
383 }
384
385 pub fn has_year_month(&self) -> bool {
387 self.years != 0 || self.months != 0
388 }
389
390 pub fn has_day(&self) -> bool {
392 self.days != 0
393 }
394
395 pub fn has_time_part_positive(&self) -> bool {
397 self.hours > 0 || self.minutes > 0 || self.seconds > 0 || self.microseconds > 0
398 }
399
400 pub fn has_time_part(&self) -> bool {
402 self.hours != 0 || self.minutes != 0 || self.seconds != 0 || self.microseconds != 0
403 }
404
405 pub fn to_iso8601_string(&self) -> String {
409 if self.is_zero() {
410 return "PT0S".to_string();
411 }
412 let fract_str = match self.microseconds {
413 0 => String::default(),
414 _ => format!(".{:06}", self.microseconds)
415 .trim_end_matches('0')
416 .to_string(),
417 };
418 format!(
419 "P{}Y{}M{}DT{}H{}M{}{}S",
420 self.years, self.months, self.days, self.hours, self.minutes, self.seconds, fract_str
421 )
422 }
423
424 pub fn to_sql_standard_string(self) -> String {
428 if self.is_zero() {
429 "0".to_string()
430 } else if !self.has_time_part() && !self.has_day() {
431 get_year_month(self.months, self.years, true)
432 } else if !self.has_time_part() && !self.has_year_month() {
433 format!("{} 0:00:00", self.days)
434 } else if !self.has_year_month() && !self.has_day() {
435 get_time_part(
436 self.hours,
437 self.minutes,
438 self.seconds,
439 self.microseconds,
440 self.has_time_part_positive(),
441 true,
442 )
443 } else {
444 let year_month = get_year_month(self.months, self.years, false);
445 let time_interval = get_time_part(
446 self.hours,
447 self.minutes,
448 self.seconds,
449 self.microseconds,
450 self.has_time_part_positive(),
451 false,
452 );
453 format!("{} {:+} {}", year_month, self.days, time_interval)
454 }
455 }
456
457 pub fn to_postgres_string(&self) -> String {
461 if self.is_zero() {
462 return "00:00:00".to_string();
463 }
464 let mut result = String::default();
465 if self.has_year_month() {
466 if self.years != 0 {
467 result.push_str(&format!("{} year ", self.years));
468 }
469 if self.months != 0 {
470 result.push_str(&format!("{} mons ", self.months));
471 }
472 }
473 if self.has_day() {
474 result.push_str(&format!("{} days ", self.days));
475 }
476 result.push_str(&self.get_postgres_time_part());
477 result.trim().to_string()
478 }
479
480 fn get_postgres_time_part(&self) -> String {
482 let mut time_part = String::default();
483 if self.has_time_part() {
484 let sign = if !self.has_time_part_positive() {
485 "-"
486 } else {
487 ""
488 };
489 let hours = Self::padding_i64(self.hours);
490 time_part.push_str(&format!(
491 "{}{}:{}:{}",
492 sign,
493 hours,
494 Self::padding_i64(self.minutes),
495 Self::padding_i64(self.seconds),
496 ));
497 if self.microseconds != 0 {
498 time_part.push_str(&format!(".{:06}", self.microseconds.unsigned_abs()))
499 }
500 }
501 time_part
502 }
503
504 fn padding_i64(val: i64) -> String {
506 let num = if val < 0 {
507 val.unsigned_abs()
508 } else {
509 val as u64
510 };
511 format!("{:02}", num)
512 }
513}
514
515fn get_year_month(mons: i32, years: i32, is_only_year_month: bool) -> String {
517 let months = mons.unsigned_abs();
518 if years == 0 || is_only_year_month {
519 format!("{}-{}", years, months)
520 } else {
521 format!("{:+}-{}", years, months)
522 }
523}
524
525fn get_time_part(
527 hours: i64,
528 mins: i64,
529 secs: i64,
530 micros: i64,
531 is_time_part_positive: bool,
532 is_only_time: bool,
533) -> String {
534 let mut interval = String::default();
535 if is_time_part_positive && is_only_time {
536 interval.push_str(&format!("{}:{:02}:{:02}", hours, mins, secs));
537 } else {
538 let minutes = mins.unsigned_abs();
539 let seconds = secs.unsigned_abs();
540 interval.push_str(&format!("{:+}:{:02}:{:02}", hours, minutes, seconds));
541 }
542 if micros != 0 {
543 let microseconds = format!(".{:06}", micros.unsigned_abs());
544 interval.push_str(µseconds);
545 }
546 interval
547}
548
549#[cfg(test)]
550mod tests {
551 use super::*;
552
553 #[test]
554 fn test_from_year_month() {
555 let interval = IntervalYearMonth::new(1);
556 assert_eq!(interval.months, 1);
557 }
558
559 #[test]
560 fn test_from_date_time() {
561 let interval = IntervalDayTime::new(1, 2);
562 assert_eq!(interval.days, 1);
563 assert_eq!(interval.milliseconds, 2);
564 }
565
566 #[test]
567 fn test_from_month_day_nano() {
568 let interval = IntervalMonthDayNano::new(1, 2, 3);
569 assert_eq!(interval.months, 1);
570 assert_eq!(interval.days, 2);
571 assert_eq!(interval.nanoseconds, 3);
572 }
573
574 #[test]
575 fn test_interval_i128_convert() {
576 let test_interval_eq = |month, day, nano| {
577 let interval = IntervalMonthDayNano::new(month, day, nano);
578 let interval_i128 = interval.to_i128();
579 let interval2 = IntervalMonthDayNano::from_i128(interval_i128);
580 assert_eq!(interval, interval2);
581 };
582
583 test_interval_eq(1, 2, 3);
584 test_interval_eq(1, -2, 3);
585 test_interval_eq(1, -2, -3);
586 test_interval_eq(-1, -2, -3);
587 test_interval_eq(i32::MAX, i32::MAX, i64::MAX);
588 test_interval_eq(i32::MIN, i32::MAX, i64::MAX);
589 test_interval_eq(i32::MAX, i32::MIN, i64::MAX);
590 test_interval_eq(i32::MAX, i32::MAX, i64::MIN);
591 test_interval_eq(i32::MIN, i32::MIN, i64::MAX);
592 test_interval_eq(i32::MAX, i32::MIN, i64::MIN);
593 test_interval_eq(i32::MIN, i32::MAX, i64::MIN);
594 test_interval_eq(i32::MIN, i32::MIN, i64::MIN);
595
596 let interval = IntervalMonthDayNano::from_i128(1);
597 assert_eq!(interval, IntervalMonthDayNano::new(0, 0, 1));
598 assert_eq!(1, IntervalMonthDayNano::new(0, 0, 1).to_i128());
599 }
600
601 #[test]
602 fn test_interval_i64_convert() {
603 let interval = IntervalDayTime::from_i64(1);
604 assert_eq!(interval, IntervalDayTime::new(0, 1));
605 assert_eq!(1, IntervalDayTime::new(0, 1).to_i64());
606 }
607
608 #[test]
609 fn test_convert_interval_format() {
610 let interval = IntervalMonthDayNano {
611 months: 14,
612 days: 160,
613 nanoseconds: 1000000,
614 };
615 let interval_format = IntervalFormat::from(interval);
616 assert_eq!(interval_format.years, 1);
617 assert_eq!(interval_format.months, 2);
618 assert_eq!(interval_format.days, 160);
619 assert_eq!(interval_format.hours, 0);
620 assert_eq!(interval_format.minutes, 0);
621 assert_eq!(interval_format.seconds, 0);
622 assert_eq!(interval_format.microseconds, 1000);
623 }
624
625 #[test]
626 fn test_to_iso8601_string() {
627 let interval = IntervalMonthDayNano::new(0, 0, 0);
629 assert_eq!(interval.to_iso8601_string(), "PT0S");
630
631 let interval = IntervalMonthDayNano::new(1, 1, 1);
632 assert_eq!(interval.to_iso8601_string(), "P0Y1M1DT0H0M0S");
633
634 let interval = IntervalMonthDayNano::new(14, 31, 10000000000);
635 assert_eq!(interval.to_iso8601_string(), "P1Y2M31DT0H0M10S");
636
637 let interval = IntervalMonthDayNano::new(14, 31, 23210200000000);
638 assert_eq!(interval.to_iso8601_string(), "P1Y2M31DT6H26M50.2S");
639 }
640
641 #[test]
642 fn test_to_postgres_string() {
643 let interval = IntervalMonthDayNano::new(0, 0, 0);
645 assert_eq!(
646 IntervalFormat::from(interval).to_postgres_string(),
647 "00:00:00"
648 );
649
650 let interval = IntervalMonthDayNano::new(23, 100, 23210200000000);
651 assert_eq!(
652 IntervalFormat::from(interval).to_postgres_string(),
653 "1 year 11 mons 100 days 06:26:50.200000"
654 );
655 }
656
657 #[test]
658 fn test_to_sql_standard_string() {
659 let interval = IntervalMonthDayNano::new(0, 0, 0);
661 assert_eq!(IntervalFormat::from(interval).to_sql_standard_string(), "0");
662
663 let interval = IntervalMonthDayNano::new(23, 100, 23210200000000);
664 assert_eq!(
665 IntervalFormat::from(interval).to_sql_standard_string(),
666 "+1-11 +100 +6:26:50.200000"
667 );
668
669 let interval = IntervalMonthDayNano::new(0, 0, 23210200000000);
671 assert_eq!(
672 IntervalFormat::from(interval).to_sql_standard_string(),
673 "6:26:50.200000"
674 );
675 }
676
677 #[test]
678 fn test_from_arrow_interval_unit() {
679 let unit = ArrowIntervalUnit::YearMonth;
680 assert_eq!(IntervalUnit::from(unit), IntervalUnit::YearMonth);
681
682 let unit = ArrowIntervalUnit::DayTime;
683 assert_eq!(IntervalUnit::from(unit), IntervalUnit::DayTime);
684
685 let unit = ArrowIntervalUnit::MonthDayNano;
686 assert_eq!(IntervalUnit::from(unit), IntervalUnit::MonthDayNano);
687 }
688}