1use std::cmp::Ordering;
16use std::error::Error;
17use std::fmt::{Display, Formatter};
18use std::hash::{Hash, Hasher};
19use std::io::{Cursor, Write};
20use std::ops::{Add, Neg, Sub};
21use std::sync::LazyLock;
22
23use anyhow::Context;
24use byteorder::{BigEndian, NetworkEndian, ReadBytesExt, WriteBytesExt};
25use bytes::BytesMut;
26use num_traits::{CheckedAdd, CheckedNeg, CheckedSub, Zero};
27use postgres_types::to_sql_checked;
28use regex::Regex;
29use risingwave_pb::data::PbInterval;
30use rust_decimal::prelude::Decimal;
31
32use super::*;
33
34#[derive(Debug, Clone, Copy, Default)]
44pub struct Interval {
45 months: i32,
46 days: i32,
47 usecs: i64,
48}
49
50impl ZeroHeapSize for Interval {}
51
52const USECS_PER_SEC: i64 = 1_000_000;
53const USECS_PER_DAY: i64 = 86400 * USECS_PER_SEC;
54const USECS_PER_MONTH: i64 = 30 * USECS_PER_DAY;
55
56impl Interval {
57 pub const MIN: Self = Self {
59 months: i32::MIN,
60 days: i32::MIN,
61 usecs: i64::MIN,
62 };
63 pub const USECS_PER_DAY: i64 = USECS_PER_DAY;
64 pub const USECS_PER_MONTH: i64 = USECS_PER_MONTH;
65 pub const USECS_PER_SEC: i64 = USECS_PER_SEC;
66
67 pub fn from_month_day_usec(months: i32, days: i32, usecs: i64) -> Self {
69 Interval {
70 months,
71 days,
72 usecs,
73 }
74 }
75
76 pub fn months(&self) -> i32 {
90 self.months
91 }
92
93 pub fn days(&self) -> i32 {
95 self.days
96 }
97
98 pub fn usecs(&self) -> i64 {
105 self.usecs
106 }
107
108 pub fn usecs_of_day(&self) -> u64 {
119 self.usecs.rem_euclid(USECS_PER_DAY) as u64
120 }
121
122 pub fn years_field(&self) -> i32 {
131 self.months / 12
132 }
133
134 pub fn months_field(&self) -> i32 {
146 self.months % 12
147 }
148
149 pub fn days_field(&self) -> i32 {
158 self.days
159 }
160
161 pub fn hours_field(&self) -> i64 {
173 self.usecs / USECS_PER_SEC / 3600
174 }
175
176 pub fn minutes_field(&self) -> i32 {
188 (self.usecs / USECS_PER_SEC / 60 % 60) as i32
189 }
190
191 pub fn seconds_in_micros(&self) -> i32 {
204 (self.usecs % (USECS_PER_SEC * 60)) as i32
205 }
206
207 pub fn epoch_in_micros(&self) -> i128 {
212 const DAYS_PER_YEAR_X4: i32 = 365 * 4 + 1;
215 const DAYS_PER_MONTH: i32 = 30;
216 const SECS_PER_DAY: i32 = 86400;
217 const MONTHS_PER_YEAR: i32 = 12;
218
219 let secs_from_day_month = ((DAYS_PER_YEAR_X4 as i64)
225 * (self.months / MONTHS_PER_YEAR) as i64
226 + (4 * DAYS_PER_MONTH as i64) * (self.months % MONTHS_PER_YEAR) as i64
227 + 4 * self.days as i64)
228 * (SECS_PER_DAY / 4) as i64;
229
230 secs_from_day_month as i128 * USECS_PER_SEC as i128 + self.usecs as i128
231 }
232
233 pub fn from_protobuf(cursor: &mut Cursor<&[u8]>) -> ArrayResult<Interval> {
234 let mut read = || {
235 let months = cursor.read_i32::<BigEndian>()?;
236 let days = cursor.read_i32::<BigEndian>()?;
237 let usecs = cursor.read_i64::<BigEndian>()?;
238
239 Ok::<_, std::io::Error>(Interval::from_month_day_usec(months, days, usecs))
240 };
241
242 Ok(read().context("failed to read Interval from buffer")?)
243 }
244
245 pub fn to_protobuf<T: Write>(self, output: &mut T) -> ArrayResult<usize> {
246 output.write_i32::<BigEndian>(self.months)?;
247 output.write_i32::<BigEndian>(self.days)?;
248 output.write_i64::<BigEndian>(self.usecs)?;
249 Ok(16)
250 }
251
252 pub fn checked_mul_int<I>(&self, rhs: I) -> Option<Self>
254 where
255 I: TryInto<i32>,
256 {
257 let rhs = rhs.try_into().ok()?;
258 let months = self.months.checked_mul(rhs)?;
259 let days = self.days.checked_mul(rhs)?;
260 let usecs = self.usecs.checked_mul(rhs as i64)?;
261
262 Some(Interval {
263 months,
264 days,
265 usecs,
266 })
267 }
268
269 fn from_floats(months: f64, days: f64, usecs: f64) -> Option<Self> {
272 let months_round_usecs = |months: f64| {
275 (months * (USECS_PER_MONTH as f64)).round_ties_even() / (USECS_PER_MONTH as f64)
276 };
277
278 let days_round_usecs =
279 |days: f64| (days * (USECS_PER_DAY as f64)).round_ties_even() / (USECS_PER_DAY as f64);
280
281 let trunc_fract = |num: f64| (num.trunc(), num.fract());
282
283 let (months, months_fract) = trunc_fract(months_round_usecs(months));
285 if months.is_nan() || months < i32::MIN.into() || months > i32::MAX.into() {
286 return None;
287 }
288 let months = months as i32;
289 let (leftover_days, leftover_days_fract) =
290 trunc_fract(days_round_usecs(months_fract * 30.));
291
292 let (days, days_fract) = trunc_fract(days_round_usecs(days));
294 if days.is_nan() || days < i32::MIN.into() || days > i32::MAX.into() {
295 return None;
296 }
297 let (days_fract_whole, days_fract) =
305 trunc_fract(days_round_usecs(days_fract + leftover_days_fract));
306 let days = (days as i32)
307 .checked_add(leftover_days as i32)?
308 .checked_add(days_fract_whole as i32)?;
309 let leftover_usecs = days_fract * (USECS_PER_DAY as f64);
310
311 let result_usecs = usecs + leftover_usecs;
313 let usecs = result_usecs.round_ties_even();
314 if usecs.is_nan() || usecs < (i64::MIN as f64) || usecs > (i64::MAX as f64) {
315 return None;
316 }
317 let usecs = usecs as i64;
318
319 Some(Self {
320 months,
321 days,
322 usecs,
323 })
324 }
325
326 pub fn div_float<I>(&self, rhs: I) -> Option<Self>
328 where
329 I: TryInto<F64>,
330 {
331 let rhs = rhs.try_into().ok()?;
332 let rhs = rhs.0;
333
334 if rhs == 0.0 {
335 return None;
336 }
337
338 Self::from_floats(
339 self.months as f64 / rhs,
340 self.days as f64 / rhs,
341 self.usecs as f64 / rhs,
342 )
343 }
344
345 pub fn mul_float<I>(&self, rhs: I) -> Option<Self>
347 where
348 I: TryInto<F64>,
349 {
350 let rhs = rhs.try_into().ok()?;
351 let rhs = rhs.0;
352
353 Self::from_floats(
354 self.months as f64 * rhs,
355 self.days as f64 * rhs,
356 self.usecs as f64 * rhs,
357 )
358 }
359
360 pub fn exact_div(&self, rhs: &Self) -> Option<i64> {
362 let mut res = None;
363 let mut check_unit = |l: i64, r: i64| {
364 if l == 0 && r == 0 {
365 return Some(());
366 }
367 if l != 0 && r == 0 {
368 return None;
369 }
370 if l % r != 0 {
371 return None;
372 }
373 let new_res = l / r;
374 if let Some(old_res) = res {
375 if old_res != new_res {
376 return None;
377 }
378 } else {
379 res = Some(new_res);
380 }
381
382 Some(())
383 };
384
385 check_unit(self.months as i64, rhs.months as i64)?;
386 check_unit(self.days as i64, rhs.days as i64)?;
387 check_unit(self.usecs, rhs.usecs)?;
388
389 res
390 }
391
392 pub fn is_positive(&self) -> bool {
394 self > &Self::from_month_day_usec(0, 0, 0)
395 }
396
397 pub fn is_never_negative(&self) -> bool {
399 self.months >= 0 && self.days >= 0 && self.usecs >= 0
400 }
401
402 pub const fn truncate_millis(self) -> Self {
414 Interval {
415 months: self.months,
416 days: self.days,
417 usecs: self.usecs / 1000 * 1000,
418 }
419 }
420
421 pub const fn truncate_second(self) -> Self {
433 Interval {
434 months: self.months,
435 days: self.days,
436 usecs: self.usecs / USECS_PER_SEC * USECS_PER_SEC,
437 }
438 }
439
440 pub const fn truncate_minute(self) -> Self {
452 Interval {
453 months: self.months,
454 days: self.days,
455 usecs: self.usecs / USECS_PER_SEC / 60 * USECS_PER_SEC * 60,
456 }
457 }
458
459 pub const fn truncate_hour(self) -> Self {
471 Interval {
472 months: self.months,
473 days: self.days,
474 usecs: self.usecs / USECS_PER_SEC / 60 / 60 * USECS_PER_SEC * 60 * 60,
475 }
476 }
477
478 pub const fn truncate_day(self) -> Self {
487 Interval {
488 months: self.months,
489 days: self.days,
490 usecs: 0,
491 }
492 }
493
494 pub const fn truncate_month(self) -> Self {
503 Interval {
504 months: self.months,
505 days: 0,
506 usecs: 0,
507 }
508 }
509
510 pub const fn truncate_quarter(self) -> Self {
519 Interval {
520 months: self.months / 3 * 3,
521 days: 0,
522 usecs: 0,
523 }
524 }
525
526 pub const fn truncate_year(self) -> Self {
535 Interval {
536 months: self.months / 12 * 12,
537 days: 0,
538 usecs: 0,
539 }
540 }
541
542 pub const fn truncate_decade(self) -> Self {
551 Interval {
552 months: self.months / 12 / 10 * 12 * 10,
553 days: 0,
554 usecs: 0,
555 }
556 }
557
558 pub const fn truncate_century(self) -> Self {
567 Interval {
568 months: self.months / 12 / 100 * 12 * 100,
569 days: 0,
570 usecs: 0,
571 }
572 }
573
574 pub const fn truncate_millennium(self) -> Self {
583 Interval {
584 months: self.months / 12 / 1000 * 12 * 1000,
585 days: 0,
586 usecs: 0,
587 }
588 }
589
590 pub fn justify_hour(self) -> Option<Self> {
593 let whole_day = (self.usecs / USECS_PER_DAY) as i32;
594 let mut usecs = self.usecs % USECS_PER_DAY;
595 let mut days = self.days.checked_add(whole_day)?;
596 if days > 0 && usecs < 0 {
597 usecs += USECS_PER_DAY;
598 days -= 1;
599 } else if days < 0 && usecs > 0 {
600 usecs -= USECS_PER_DAY;
601 days += 1;
602 }
603 Some(Self::from_month_day_usec(self.months, days, usecs))
604 }
605}
606
607pub mod test_utils {
610 use super::*;
611
612 pub trait IntervalTestExt {
614 fn from_ymd(year: i32, month: i32, days: i32) -> Self;
615 fn from_month(months: i32) -> Self;
616 fn from_days(days: i32) -> Self;
617 fn from_millis(ms: i64) -> Self;
618 fn from_minutes(minutes: i64) -> Self;
619 }
620
621 impl IntervalTestExt for Interval {
622 fn from_ymd(year: i32, month: i32, days: i32) -> Self {
623 let months = year * 12 + month;
624 let usecs = 0;
625 Interval {
626 months,
627 days,
628 usecs,
629 }
630 }
631
632 fn from_month(months: i32) -> Self {
633 Interval {
634 months,
635 ..Default::default()
636 }
637 }
638
639 fn from_days(days: i32) -> Self {
640 Self {
641 days,
642 ..Default::default()
643 }
644 }
645
646 fn from_millis(ms: i64) -> Self {
647 Self {
648 usecs: ms * 1000,
649 ..Default::default()
650 }
651 }
652
653 fn from_minutes(minutes: i64) -> Self {
654 Self {
655 usecs: USECS_PER_SEC * 60 * minutes,
656 ..Default::default()
657 }
658 }
659 }
660}
661
662#[derive(Clone, Copy)]
665pub struct IntervalDisplay<'a> {
666 pub core: &'a Interval,
667}
668
669impl std::fmt::Display for IntervalDisplay<'_> {
670 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
671 (self as &dyn std::fmt::Debug).fmt(f)
672 }
673}
674
675impl std::fmt::Debug for IntervalDisplay<'_> {
676 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
677 write!(f, "{}", self.core)
678 }
679}
680
681#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
723struct IntervalCmpValue(i128);
724
725impl From<Interval> for IntervalCmpValue {
726 fn from(value: Interval) -> Self {
727 let days = (value.days as i64) + 30i64 * (value.months as i64);
728 let usecs = (value.usecs as i128) + (USECS_PER_DAY as i128) * (days as i128);
729 Self(usecs)
730 }
731}
732
733impl Ord for Interval {
734 fn cmp(&self, other: &Self) -> Ordering {
735 IntervalCmpValue::from(*self).cmp(&(*other).into())
736 }
737}
738
739impl PartialOrd for Interval {
740 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
741 Some(self.cmp(other))
742 }
743}
744
745impl PartialEq for Interval {
746 fn eq(&self, other: &Self) -> bool {
747 self.cmp(other).is_eq()
748 }
749}
750
751impl Eq for Interval {}
752
753impl Hash for Interval {
754 fn hash<H: Hasher>(&self, state: &mut H) {
755 IntervalCmpValue::from(*self).hash(state);
756 }
757}
758
759impl Serialize for Interval {
762 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
763 where
764 S: serde::Serializer,
765 {
766 let cmp_value = IntervalCmpValue::from(*self);
767 cmp_value.0.serialize(serializer)
768 }
769}
770
771impl IntervalCmpValue {
772 fn as_justified(&self) -> Option<Interval> {
774 let usecs = (self.0 % (USECS_PER_DAY as i128)) as i64;
775 let remaining_days = self.0 / (USECS_PER_DAY as i128);
776 let days = (remaining_days % 30) as i32;
777 let months = (remaining_days / 30).try_into().ok()?;
778 Some(Interval::from_month_day_usec(months, days, usecs))
779 }
780
781 fn as_alternate(&self) -> Option<Interval> {
784 match self.0.cmp(&0) {
785 Ordering::Equal => Some(Interval::from_month_day_usec(0, 0, 0)),
786 Ordering::Greater => {
787 let remaining_usecs = self.0;
788 let mut usecs = (remaining_usecs % (USECS_PER_DAY as i128)) as i64;
789 let mut remaining_days = remaining_usecs / (USECS_PER_DAY as i128);
790 let extra_days = ((i64::MAX - usecs) / USECS_PER_DAY)
796 .min(remaining_days.try_into().unwrap_or(i64::MAX));
797 usecs += extra_days * USECS_PER_DAY;
799 remaining_days -= extra_days as i128;
801
802 let mut days = (remaining_days % 30) as i32;
804 let mut remaining_months = remaining_days / 30;
805 let extra_months =
806 ((i32::MAX - days) / 30).min(remaining_months.try_into().unwrap_or(i32::MAX));
807 days += extra_months * 30;
808 remaining_months -= extra_months as i128;
809
810 let months = remaining_months.try_into().ok()?;
811 Some(Interval::from_month_day_usec(months, days, usecs))
812 }
813 Ordering::Less => {
814 let remaining_usecs = self.0;
815 let mut usecs = (remaining_usecs % (USECS_PER_DAY as i128)) as i64;
816 let mut remaining_days = remaining_usecs / (USECS_PER_DAY as i128);
817 let extra_days = ((i64::MIN - usecs) / USECS_PER_DAY)
820 .max(remaining_days.try_into().unwrap_or(i64::MIN));
821 usecs += extra_days * USECS_PER_DAY;
822 remaining_days -= extra_days as i128;
823
824 let mut days = (remaining_days % 30) as i32;
825 let mut remaining_months = remaining_days / 30;
826 let extra_months =
827 ((i32::MIN - days) / 30).max(remaining_months.try_into().unwrap_or(i32::MIN));
828 days += extra_months * 30;
829 remaining_months -= extra_months as i128;
830
831 let months = remaining_months.try_into().ok()?;
832 Some(Interval::from_month_day_usec(months, days, usecs))
833 }
834 }
835 }
836}
837
838impl<'de> Deserialize<'de> for Interval {
839 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
840 where
841 D: serde::Deserializer<'de>,
842 {
843 let cmp_value = IntervalCmpValue(i128::deserialize(deserializer)?);
844 let interval = cmp_value
845 .as_justified()
846 .or_else(|| cmp_value.as_alternate());
847 interval.ok_or_else(|| {
848 use serde::de::Error as _;
849 D::Error::custom("memcomparable deserialize interval overflow")
850 })
851 }
852}
853
854impl crate::hash::HashKeySer<'_> for Interval {
855 fn serialize_into(self, mut buf: impl BufMut) {
856 let cmp_value = IntervalCmpValue::from(self);
857 let b = cmp_value.0.to_ne_bytes();
858 buf.put_slice(&b);
859 }
860
861 fn exact_size() -> Option<usize> {
862 Some(16)
863 }
864}
865
866impl crate::hash::HashKeyDe for Interval {
867 fn deserialize(_data_type: &DataType, mut buf: impl Buf) -> Self {
868 let value = buf.get_i128_ne();
869 let cmp_value = IntervalCmpValue(value);
870 cmp_value
871 .as_justified()
872 .or_else(|| cmp_value.as_alternate())
873 .expect("HashKey deserialize interval overflow")
874 }
875}
876
877#[expect(clippy::from_over_into)]
879impl Into<PbInterval> for Interval {
880 fn into(self) -> PbInterval {
881 PbInterval {
882 months: self.months,
883 days: self.days,
884 usecs: self.usecs,
885 }
886 }
887}
888
889impl From<&'_ PbInterval> for Interval {
890 fn from(p: &'_ PbInterval) -> Self {
891 Self {
892 months: p.months,
893 days: p.days,
894 usecs: p.usecs,
895 }
896 }
897}
898
899impl From<Time> for Interval {
900 fn from(time: Time) -> Self {
901 let mut usecs: i64 = (time.0.num_seconds_from_midnight() as i64) * USECS_PER_SEC;
902 usecs += (time.0.nanosecond() / 1000) as i64;
903 Self {
904 months: 0,
905 days: 0,
906 usecs,
907 }
908 }
909}
910
911impl Add for Interval {
912 type Output = Self;
913
914 fn add(self, rhs: Self) -> Self {
915 let months = self.months + rhs.months;
916 let days = self.days + rhs.days;
917 let usecs = self.usecs + rhs.usecs;
918 Interval {
919 months,
920 days,
921 usecs,
922 }
923 }
924}
925
926impl CheckedNeg for Interval {
927 fn checked_neg(&self) -> Option<Self> {
928 let months = self.months.checked_neg()?;
929 let days = self.days.checked_neg()?;
930 let usecs = self.usecs.checked_neg()?;
931 Some(Interval {
932 months,
933 days,
934 usecs,
935 })
936 }
937}
938
939impl CheckedAdd for Interval {
940 fn checked_add(&self, other: &Self) -> Option<Self> {
941 let months = self.months.checked_add(other.months)?;
942 let days = self.days.checked_add(other.days)?;
943 let usecs = self.usecs.checked_add(other.usecs)?;
944 Some(Interval {
945 months,
946 days,
947 usecs,
948 })
949 }
950}
951
952impl Sub for Interval {
953 type Output = Self;
954
955 fn sub(self, rhs: Self) -> Self {
956 let months = self.months - rhs.months;
957 let days = self.days - rhs.days;
958 let usecs = self.usecs - rhs.usecs;
959 Interval {
960 months,
961 days,
962 usecs,
963 }
964 }
965}
966
967impl CheckedSub for Interval {
968 fn checked_sub(&self, other: &Self) -> Option<Self> {
969 let months = self.months.checked_sub(other.months)?;
970 let days = self.days.checked_sub(other.days)?;
971 let usecs = self.usecs.checked_sub(other.usecs)?;
972 Some(Interval {
973 months,
974 days,
975 usecs,
976 })
977 }
978}
979
980impl Zero for Interval {
981 fn zero() -> Self {
982 Self::from_month_day_usec(0, 0, 0)
983 }
984
985 fn is_zero(&self) -> bool {
986 self.months == 0 && self.days == 0 && self.usecs == 0
987 }
988}
989
990impl Neg for Interval {
991 type Output = Self;
992
993 fn neg(self) -> Self {
994 Self {
995 months: -self.months,
996 days: -self.days,
997 usecs: -self.usecs,
998 }
999 }
1000}
1001
1002impl ToText for crate::types::Interval {
1003 fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
1004 write!(f, "{self}")
1005 }
1006
1007 fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
1008 match ty {
1009 DataType::Interval => self.write(f),
1010 _ => unreachable!(),
1011 }
1012 }
1013}
1014
1015#[derive(thiserror::Error, Debug, thiserror_ext::Construct)]
1017pub enum IntervalParseError {
1018 #[error("Invalid interval: {0}")]
1019 Invalid(String),
1020
1021 #[error(
1022 "Invalid interval: {0}, expected format P<years>Y<months>M<days>DT<hours>H<minutes>M<seconds>S"
1023 )]
1024 InvalidIso8601(String),
1025
1026 #[error("Invalid unit: {0}")]
1027 InvalidUnit(String),
1028
1029 #[error("{0}")]
1030 Uncategorized(String),
1031}
1032
1033type ParseResult<T> = std::result::Result<T, IntervalParseError>;
1034
1035impl Interval {
1036 pub fn as_iso_8601(&self) -> String {
1037 let years = self.months / 12;
1039 let months = self.months % 12;
1040 let days = self.days;
1041 let secs_fract = (self.usecs % USECS_PER_SEC).abs();
1042 let total_secs = (self.usecs / USECS_PER_SEC).abs();
1043 let hours = total_secs / 3600;
1044 let minutes = (total_secs / 60) % 60;
1045 let seconds = total_secs % 60;
1046 let mut buf = [0u8; 7];
1047 let fract_str = if secs_fract != 0 {
1048 write!(buf.as_mut_slice(), ".{:06}", secs_fract).unwrap();
1049 std::str::from_utf8(&buf).unwrap().trim_end_matches('0')
1050 } else {
1051 ""
1052 };
1053 format!("P{years}Y{months}M{days}DT{hours}H{minutes}M{seconds}{fract_str}S")
1054 }
1055
1056 pub fn from_iso_8601(s: &str) -> ParseResult<Self> {
1064 static ISO_8601_REGEX: LazyLock<Regex> = LazyLock::new(|| {
1066 Regex::new(r"^P([0-9]+)Y([0-9]+)M([0-9]+)DT([0-9]+)H([0-9]+)M([0-9]+(?:\.[0-9]+)?)S$")
1067 .unwrap()
1068 });
1069 let f = || {
1071 let caps = ISO_8601_REGEX.captures(s)?;
1072 let years: i32 = caps[1].parse().ok()?;
1073 let months: i32 = caps[2].parse().ok()?;
1074 let days = caps[3].parse().ok()?;
1075 let hours: i64 = caps[4].parse().ok()?;
1076 let minutes: i64 = caps[5].parse().ok()?;
1077 let usecs: i64 = (Decimal::from_str_exact(&caps[6])
1079 .ok()?
1080 .checked_mul(Decimal::from_str_exact("1000000").unwrap()))?
1081 .try_into()
1082 .ok()?;
1083 Some(Interval::from_month_day_usec(
1084 years.checked_mul(12)?.checked_add(months)?,
1086 days,
1087 (hours
1089 .checked_mul(3_600)?
1090 .checked_add(minutes.checked_mul(60)?))?
1091 .checked_mul(USECS_PER_SEC)?
1092 .checked_add(usecs)?,
1093 ))
1094 };
1095 f().ok_or_else(|| IntervalParseError::invalid_iso8601(s))
1096 }
1097}
1098
1099impl Display for Interval {
1100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1101 let years = self.months / 12;
1102 let months = self.months % 12;
1103 let days = self.days;
1104 let mut space = false;
1105 let mut following_neg = false;
1106 let mut write_i32 = |arg: i32, unit: &str| -> std::fmt::Result {
1107 if arg == 0 {
1108 return Ok(());
1109 }
1110 if space {
1111 write!(f, " ")?;
1112 }
1113 if following_neg && arg > 0 {
1114 write!(f, "+")?;
1115 }
1116 write!(f, "{arg} {unit}")?;
1117 if arg != 1 {
1118 write!(f, "s")?;
1119 }
1120 space = true;
1121 following_neg = arg < 0;
1122 Ok(())
1123 };
1124 write_i32(years, "year")?;
1125 write_i32(months, "mon")?;
1126 write_i32(days, "day")?;
1127 if self.usecs != 0 || self.months == 0 && self.days == 0 {
1128 let secs_fract = (self.usecs % USECS_PER_SEC).abs();
1130 let total_secs = (self.usecs / USECS_PER_SEC).abs();
1131 let hours = total_secs / 3600;
1132 let minutes = (total_secs / 60) % 60;
1133 let seconds = total_secs % 60;
1134
1135 if space {
1136 write!(f, " ")?;
1137 }
1138 if following_neg && self.usecs > 0 {
1139 write!(f, "+")?;
1140 } else if self.usecs < 0 {
1141 write!(f, "-")?;
1142 }
1143 write!(f, "{hours:0>2}:{minutes:0>2}:{seconds:0>2}")?;
1144 if secs_fract != 0 {
1145 let mut buf = [0u8; 7];
1146 write!(buf.as_mut_slice(), ".{:06}", secs_fract).unwrap();
1147 write!(
1148 f,
1149 "{}",
1150 std::str::from_utf8(&buf).unwrap().trim_end_matches('0')
1151 )?;
1152 }
1153 }
1154 Ok(())
1155 }
1156}
1157
1158impl ToSql for Interval {
1159 to_sql_checked!();
1160
1161 fn to_sql(
1162 &self,
1163 _: &Type,
1164 out: &mut BytesMut,
1165 ) -> std::result::Result<IsNull, Box<dyn Error + 'static + Send + Sync>> {
1166 out.put_i64(self.usecs);
1168 out.put_i32(self.days);
1169 out.put_i32(self.months);
1170 Ok(IsNull::No)
1171 }
1172
1173 fn accepts(ty: &Type) -> bool {
1174 matches!(*ty, Type::INTERVAL)
1175 }
1176}
1177
1178impl<'a> FromSql<'a> for Interval {
1179 fn from_sql(
1180 _: &Type,
1181 mut raw: &'a [u8],
1182 ) -> std::result::Result<Interval, Box<dyn Error + Sync + Send>> {
1183 let usecs = raw.read_i64::<NetworkEndian>()?;
1184 let days = raw.read_i32::<NetworkEndian>()?;
1185 let months = raw.read_i32::<NetworkEndian>()?;
1186 Ok(Interval::from_month_day_usec(months, days, usecs))
1187 }
1188
1189 fn accepts(ty: &Type) -> bool {
1190 matches!(*ty, Type::INTERVAL)
1191 }
1192}
1193
1194#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1195pub enum DateTimeField {
1196 Year,
1197 Month,
1198 Day,
1199 Hour,
1200 Minute,
1201 Second,
1202}
1203
1204impl FromStr for DateTimeField {
1205 type Err = IntervalParseError;
1206
1207 fn from_str(s: &str) -> ParseResult<Self> {
1208 match s.to_lowercase().as_str() {
1209 "years" | "year" | "yrs" | "yr" | "y" => Ok(Self::Year),
1210 "days" | "day" | "d" => Ok(Self::Day),
1211 "hours" | "hour" | "hrs" | "hr" | "h" => Ok(Self::Hour),
1212 "minutes" | "minute" | "mins" | "min" | "m" => Ok(Self::Minute),
1213 "months" | "month" | "mons" | "mon" => Ok(Self::Month),
1214 "seconds" | "second" | "secs" | "sec" | "s" => Ok(Self::Second),
1215 _ => Err(IntervalParseError::invalid_unit(s)),
1216 }
1217 }
1218}
1219
1220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1221enum TimeStrToken {
1222 Second(F64),
1223 Num(i64),
1224 TimeUnit(DateTimeField),
1225}
1226
1227fn parse_interval(s: &str) -> ParseResult<Vec<TimeStrToken>> {
1228 let s = s.trim();
1229 let mut tokens = Vec::new();
1230 let mut num_buf = "".to_owned();
1231 let mut char_buf = "".to_owned();
1232 let mut hour_min_sec = Vec::new();
1233 for (i, c) in s.chars().enumerate() {
1234 match c {
1235 '-' | '+' => {
1236 num_buf.push(c);
1237 }
1238 '.' => {
1239 num_buf.push(c);
1240 }
1241 c if c.is_ascii_digit() => {
1242 convert_unit(&mut char_buf, &mut tokens)?;
1243 num_buf.push(c);
1244 }
1245 c if c.is_ascii_alphabetic() => {
1246 convert_digit(&mut num_buf, &mut tokens)?;
1247 char_buf.push(c);
1248 }
1249 chr if chr.is_ascii_whitespace() => {
1250 convert_unit(&mut char_buf, &mut tokens)?;
1251 if !matches!(num_buf.as_str(), "-" | "+") {
1253 convert_digit(&mut num_buf, &mut tokens)?;
1254 }
1255 }
1256 ':' => {
1257 if num_buf.is_empty() {
1259 return Err(IntervalParseError::invalid(s));
1260 }
1261 hour_min_sec.push(num_buf.clone());
1262 num_buf.clear();
1263 }
1264 _ => {
1265 return Err(IntervalParseError::uncategorized(format!(
1266 "Invalid character at offset {} in {}: {:?}. Only support digit or alphabetic now",
1267 i, s, c
1268 )));
1269 }
1270 };
1271 }
1272 if !hour_min_sec.is_empty() {
1273 if !num_buf.is_empty() {
1274 hour_min_sec.push(num_buf.clone());
1275 num_buf.clear();
1276 }
1277 } else {
1278 convert_digit(&mut num_buf, &mut tokens)?;
1279 }
1280 convert_unit(&mut char_buf, &mut tokens)?;
1281 convert_hms(&hour_min_sec, &mut tokens)
1282 .ok_or_else(|| IntervalParseError::invalid(format!("{hour_min_sec:?}")))?;
1283
1284 Ok(tokens)
1285}
1286
1287fn convert_digit(c: &mut String, t: &mut Vec<TimeStrToken>) -> ParseResult<()> {
1288 if !c.is_empty() {
1289 match c.parse::<i64>() {
1290 Ok(num) => {
1291 t.push(TimeStrToken::Num(num));
1292 }
1293 Err(_) => {
1294 return Err(IntervalParseError::invalid(c.clone()));
1295 }
1296 }
1297 c.clear();
1298 }
1299 Ok(())
1300}
1301
1302fn convert_unit(c: &mut String, t: &mut Vec<TimeStrToken>) -> ParseResult<()> {
1303 if !c.is_empty() {
1304 t.push(TimeStrToken::TimeUnit(c.parse()?));
1305 c.clear();
1306 }
1307 Ok(())
1308}
1309
1310fn convert_hms(c: &Vec<String>, t: &mut Vec<TimeStrToken>) -> Option<()> {
1317 if c.len() > 3 {
1318 return None;
1319 }
1320 let mut is_neg = false;
1321 if let Some(s) = c.first() {
1322 let v = s.parse().ok()?;
1323 is_neg = s.starts_with('-');
1324 t.push(TimeStrToken::Num(v));
1325 t.push(TimeStrToken::TimeUnit(DateTimeField::Hour))
1326 }
1327 if let Some(s) = c.get(1) {
1328 let mut v: i64 = s.parse().ok()?;
1329 if !(0..60).contains(&v) {
1330 return None;
1331 }
1332 if is_neg {
1333 v = v.checked_neg()?;
1334 }
1335 t.push(TimeStrToken::Num(v));
1336 t.push(TimeStrToken::TimeUnit(DateTimeField::Minute))
1337 }
1338 if let Some(s) = c.get(2) {
1339 let mut v: f64 = s.parse().ok()?;
1340 if !(0f64..61f64).contains(&v) {
1342 return None;
1343 }
1344 if is_neg {
1345 v = -v;
1346 }
1347 t.push(TimeStrToken::Second(v.into()));
1348 t.push(TimeStrToken::TimeUnit(DateTimeField::Second))
1349 }
1350 Some(())
1351}
1352
1353impl Interval {
1354 fn parse_sql_standard(s: &str, leading_field: DateTimeField) -> ParseResult<Self> {
1355 use DateTimeField::*;
1356 let tokens = parse_interval(s)?;
1357 if tokens.len() > 1 {
1359 return Err(IntervalParseError::invalid(s));
1360 }
1361 let num = match tokens.first() {
1362 Some(TimeStrToken::Num(num)) => *num,
1363 _ => {
1364 return Err(IntervalParseError::invalid(s));
1365 }
1366 };
1367
1368 (|| match leading_field {
1369 Year => {
1370 let months = num.checked_mul(12)?.try_into().ok()?;
1371 Some(Interval::from_month_day_usec(months, 0, 0))
1372 }
1373 Month => Some(Interval::from_month_day_usec(num.try_into().ok()?, 0, 0)),
1374 Day => Some(Interval::from_month_day_usec(0, num.try_into().ok()?, 0)),
1375 Hour => {
1376 let usecs = num.checked_mul(3600 * USECS_PER_SEC)?;
1377 Some(Interval::from_month_day_usec(0, 0, usecs))
1378 }
1379 Minute => {
1380 let usecs = num.checked_mul(60 * USECS_PER_SEC)?;
1381 Some(Interval::from_month_day_usec(0, 0, usecs))
1382 }
1383 Second => {
1384 let usecs = num.checked_mul(USECS_PER_SEC)?;
1385 Some(Interval::from_month_day_usec(0, 0, usecs))
1386 }
1387 })()
1388 .ok_or_else(|| IntervalParseError::invalid(s))
1389 }
1390
1391 fn parse_postgres(s: &str) -> ParseResult<Self> {
1392 use DateTimeField::*;
1393 let mut tokens = parse_interval(s)?;
1394 if tokens.len() % 2 != 0
1395 && let Some(TimeStrToken::Num(_)) = tokens.last()
1396 {
1397 tokens.push(TimeStrToken::TimeUnit(DateTimeField::Second));
1398 }
1399 if tokens.len() % 2 != 0 {
1400 return Err(IntervalParseError::invalid(s));
1401 }
1402 let mut token_iter = tokens.into_iter();
1403 let mut result = Interval::from_month_day_usec(0, 0, 0);
1404 while let Some(num) = token_iter.next()
1405 && let Some(interval_unit) = token_iter.next()
1406 {
1407 match (num, interval_unit) {
1408 (TimeStrToken::Num(num), TimeStrToken::TimeUnit(interval_unit)) => {
1409 result = (|| match interval_unit {
1410 Year => {
1411 let months = num.checked_mul(12)?.try_into().ok()?;
1412 Some(Interval::from_month_day_usec(months, 0, 0))
1413 }
1414 Month => Some(Interval::from_month_day_usec(num.try_into().ok()?, 0, 0)),
1415 Day => Some(Interval::from_month_day_usec(0, num.try_into().ok()?, 0)),
1416 Hour => {
1417 let usecs = num.checked_mul(3600 * USECS_PER_SEC)?;
1418 Some(Interval::from_month_day_usec(0, 0, usecs))
1419 }
1420 Minute => {
1421 let usecs = num.checked_mul(60 * USECS_PER_SEC)?;
1422 Some(Interval::from_month_day_usec(0, 0, usecs))
1423 }
1424 Second => {
1425 let usecs = num.checked_mul(USECS_PER_SEC)?;
1426 Some(Interval::from_month_day_usec(0, 0, usecs))
1427 }
1428 })()
1429 .and_then(|rhs| result.checked_add(&rhs))
1430 .ok_or_else(|| IntervalParseError::invalid(s))?;
1431 }
1432 (TimeStrToken::Second(second), TimeStrToken::TimeUnit(interval_unit)) => {
1433 result = match interval_unit {
1434 Second => {
1435 let usecs = (second.into_inner() * (USECS_PER_SEC as f64))
1438 .round_ties_even() as i64;
1439 Some(Interval::from_month_day_usec(0, 0, usecs))
1440 }
1441 _ => None,
1442 }
1443 .and_then(|rhs| result.checked_add(&rhs))
1444 .ok_or_else(|| IntervalParseError::invalid(s))?;
1445 }
1446 _ => {
1447 return Err(IntervalParseError::invalid(s));
1448 }
1449 }
1450 }
1451 Ok(result)
1452 }
1453
1454 pub fn parse_with_fields(s: &str, leading_field: Option<DateTimeField>) -> ParseResult<Self> {
1455 if let Some(leading_field) = leading_field {
1456 Self::parse_sql_standard(s, leading_field)
1457 } else {
1458 match s.as_bytes().get(0) {
1459 Some(b'P') => Self::from_iso_8601(s),
1460 _ => Self::parse_postgres(s),
1461 }
1462 }
1463 }
1464}
1465
1466impl FromStr for Interval {
1467 type Err = IntervalParseError;
1468
1469 fn from_str(s: &str) -> ParseResult<Self> {
1470 Self::parse_with_fields(s, None)
1471 }
1472}
1473
1474#[cfg(test)]
1475mod tests {
1476 use interval::test_utils::IntervalTestExt;
1477
1478 use super::*;
1479 use crate::types::ordered_float::OrderedFloat;
1480 use crate::util::panic::rw_catch_unwind;
1481
1482 #[test]
1483 fn test_parse() {
1484 let interval = "04:00:00".parse::<Interval>().unwrap();
1485 assert_eq!(interval, Interval::from_millis(4 * 3600 * 1000));
1486
1487 let interval = "1 year 2 months 3 days 00:00:01"
1488 .parse::<Interval>()
1489 .unwrap();
1490 assert_eq!(
1491 interval,
1492 Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1000)
1493 );
1494
1495 let interval = "1 year 2 months 3 days 00:00:00.001"
1496 .parse::<Interval>()
1497 .unwrap();
1498 assert_eq!(
1499 interval,
1500 Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1)
1501 );
1502
1503 let interval = "1 year 2 months 3 days 00:59:59.005"
1504 .parse::<Interval>()
1505 .unwrap();
1506 assert_eq!(
1507 interval,
1508 Interval::from_month(14)
1509 + Interval::from_days(3)
1510 + Interval::from_minutes(59)
1511 + Interval::from_millis(59000)
1512 + Interval::from_millis(5)
1513 );
1514
1515 let interval = "1 year 2 months 3 days 01".parse::<Interval>().unwrap();
1516 assert_eq!(
1517 interval,
1518 Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1000)
1519 );
1520
1521 let interval = "1 year 2 months 3 days 1:".parse::<Interval>().unwrap();
1522 assert_eq!(
1523 interval,
1524 Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(60)
1525 );
1526
1527 let interval = "1 year 2 months 3 days 1:2".parse::<Interval>().unwrap();
1528 assert_eq!(
1529 interval,
1530 Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(62)
1531 );
1532
1533 let interval = "1 year 2 months 3 days 1:2:".parse::<Interval>().unwrap();
1534 assert_eq!(
1535 interval,
1536 Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(62)
1537 );
1538
1539 let interval = "P1Y2M3DT0H5M0S".parse::<Interval>().unwrap();
1540 assert_eq!(
1541 interval,
1542 Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(5)
1543 );
1544 }
1545
1546 #[test]
1547 fn test_to_string() {
1548 assert_eq!(
1549 Interval::from_month_day_usec(-14, 3, (11 * 3600 + 45 * 60 + 14) * USECS_PER_SEC + 233)
1550 .to_string(),
1551 "-1 years -2 mons +3 days 11:45:14.000233"
1552 );
1553 assert_eq!(
1554 Interval::from_month_day_usec(-14, 3, 0).to_string(),
1555 "-1 years -2 mons +3 days"
1556 );
1557 assert_eq!(Interval::default().to_string(), "00:00:00");
1558 assert_eq!(
1559 Interval::from_month_day_usec(
1560 -14,
1561 3,
1562 -((11 * 3600 + 45 * 60 + 14) * USECS_PER_SEC + 233)
1563 )
1564 .to_string(),
1565 "-1 years -2 mons +3 days -11:45:14.000233"
1566 );
1567 }
1568
1569 #[test]
1570 fn test_exact_div() {
1571 let cases = [
1572 ((14, 6, 6), (14, 6, 6), Some(1)),
1573 ((0, 0, 0), (0, 0, 0), None),
1574 ((0, 0, 0), (1, 0, 0), Some(0)),
1575 ((1, 1, 1), (0, 0, 0), None),
1576 ((1, 1, 1), (1, 0, 0), None),
1577 ((10, 0, 0), (1, 0, 0), Some(10)),
1578 ((10, 0, 0), (4, 0, 0), None),
1579 ((0, 24, 0), (4, 0, 0), None),
1580 ((6, 8, 9), (3, 1, 3), None),
1581 ((6, 8, 12), (3, 4, 6), Some(2)),
1582 ];
1583
1584 for (lhs, rhs, expected) in cases {
1585 let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1586 let rhs = Interval::from_month_day_usec(rhs.0, rhs.1, rhs.2 as i64);
1587 let result = rw_catch_unwind(|| {
1588 let actual = lhs.exact_div(&rhs);
1589 assert_eq!(actual, expected);
1590 });
1591 if result.is_err() {
1592 println!("Failed on {}.exact_div({})", lhs, rhs);
1593 break;
1594 }
1595 }
1596 }
1597
1598 #[test]
1599 fn test_div_float() {
1600 let cases_int = [
1601 ((10, 8, 6), 2, Some((5, 4, 3))),
1602 ((1, 2, 33), 3, Some((0, 10, 57600000011i64))),
1603 ((1, 0, 11), 10, Some((0, 3, 1))),
1604 ((5, 6, 7), 0, None),
1605 ];
1606
1607 let cases_float = [
1608 ((10, 8, 6), 2.0f32, Some((5, 4, 3))),
1609 ((1, 2, 33), 3.0f32, Some((0, 10, 57600000011i64))),
1610 ((10, 15, 100), 2.5f32, Some((4, 6, 40))),
1611 ((5, 6, 7), 0.0f32, None),
1612 ];
1613
1614 for (lhs, rhs, expected) in cases_int {
1615 let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1616 let expected = expected.map(|x| Interval::from_month_day_usec(x.0, x.1, x.2));
1617
1618 let actual = lhs.div_float(rhs as i16);
1619 assert_eq!(actual, expected);
1620
1621 let actual = lhs.div_float(rhs);
1622 assert_eq!(actual, expected);
1623
1624 let actual = lhs.div_float(rhs as i64);
1625 assert_eq!(actual, expected);
1626 }
1627
1628 for (lhs, rhs, expected) in cases_float {
1629 let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1630 let expected = expected.map(|x| Interval::from_month_day_usec(x.0, x.1, x.2));
1631
1632 let actual = lhs.div_float(OrderedFloat::<f32>(rhs));
1633 assert_eq!(actual, expected);
1634
1635 let actual = lhs.div_float(OrderedFloat::<f64>(rhs as f64));
1636 assert_eq!(actual, expected);
1637 }
1638 }
1639
1640 #[test]
1641 fn test_serialize_deserialize() {
1642 let mut serializer = memcomparable::Serializer::new(vec![]);
1643 let a = Interval::from_month_day_usec(123, 456, 789);
1644 a.serialize(&mut serializer).unwrap();
1645 let buf = serializer.into_inner();
1646 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1647 assert_eq!(Interval::deserialize(&mut deserializer).unwrap(), a);
1648 }
1649
1650 #[test]
1651 fn test_memcomparable() {
1652 let cases = [
1653 ((1, 2, 3), (4, 5, 6), Ordering::Less),
1654 ((0, 31, 0), (1, 0, 0), Ordering::Greater),
1655 ((1, 0, 0), (0, 0, USECS_PER_MONTH + 1), Ordering::Less),
1656 ((0, 1, 0), (0, 0, USECS_PER_DAY + 1), Ordering::Less),
1657 (
1658 (2, 3, 4),
1659 (1, 2, 4 + USECS_PER_DAY + USECS_PER_MONTH),
1660 Ordering::Equal,
1661 ),
1662 ];
1663
1664 for ((lhs_months, lhs_days, lhs_usecs), (rhs_months, rhs_days, rhs_usecs), order) in cases {
1665 let lhs = {
1666 let mut serializer = memcomparable::Serializer::new(vec![]);
1667 Interval::from_month_day_usec(lhs_months, lhs_days, lhs_usecs)
1668 .serialize(&mut serializer)
1669 .unwrap();
1670 serializer.into_inner()
1671 };
1672 let rhs = {
1673 let mut serializer = memcomparable::Serializer::new(vec![]);
1674 Interval::from_month_day_usec(rhs_months, rhs_days, rhs_usecs)
1675 .serialize(&mut serializer)
1676 .unwrap();
1677 serializer.into_inner()
1678 };
1679 assert_eq!(lhs.cmp(&rhs), order)
1680 }
1681 }
1682
1683 #[test]
1684 fn test_deserialize_justify() {
1685 let cases = [
1686 (
1687 (0, 0, USECS_PER_MONTH * 2 + USECS_PER_DAY * 3 + 4),
1688 Some((2, 3, 4i64, "2 mons 3 days 00:00:00.000004")),
1689 ),
1690 ((i32::MIN, i32::MIN, i64::MIN), None),
1691 ((i32::MAX, i32::MAX, i64::MAX), None),
1692 (
1693 (0, i32::MIN, i64::MIN),
1694 Some((
1695 -75141187,
1696 -29,
1697 -14454775808,
1698 "-6261765 years -7 mons -29 days -04:00:54.775808",
1699 )),
1700 ),
1701 (
1702 (i32::MIN, -60, i64::MAX),
1703 Some((
1704 -2143925250,
1705 -8,
1706 -71945224193,
1707 "-178660437 years -6 mons -8 days -19:59:05.224193",
1708 )),
1709 ),
1710 ];
1711 for ((lhs_months, lhs_days, lhs_usecs), rhs) in cases {
1712 let input = Interval::from_month_day_usec(lhs_months, lhs_days, lhs_usecs);
1713 let actual_deserialize = IntervalCmpValue::from(input).as_justified();
1714
1715 match rhs {
1716 None => {
1717 assert_eq!(actual_deserialize, None);
1718 }
1719 Some((rhs_months, rhs_days, rhs_usecs, rhs_str)) => {
1720 assert_eq!(actual_deserialize.unwrap().months(), rhs_months);
1722 assert_eq!(actual_deserialize.unwrap().days(), rhs_days);
1723 assert_eq!(actual_deserialize.unwrap().usecs(), rhs_usecs);
1724 assert_eq!(actual_deserialize.unwrap().to_string(), rhs_str);
1725 }
1726 }
1727 }
1728
1729 let input = Interval::from_month_day_usec(i32::MIN, -30, 1);
1731 let actual_deserialize = IntervalCmpValue::from(input).as_justified();
1732 assert_eq!(actual_deserialize.unwrap().months(), i32::MIN);
1734 assert_eq!(actual_deserialize.unwrap().days(), -29);
1735 assert_eq!(actual_deserialize.unwrap().usecs(), -USECS_PER_DAY + 1);
1736 }
1737
1738 #[test]
1739 fn test_deserialize_alternate() {
1740 let cases = [
1741 (0, 0, USECS_PER_MONTH * 2 + USECS_PER_DAY * 3 + 4),
1742 (i32::MIN, i32::MIN, i64::MIN),
1743 (i32::MAX, i32::MAX, i64::MAX),
1744 (0, i32::MIN, i64::MIN),
1745 (i32::MIN, -60, i64::MAX),
1746 ];
1747 for (months, days, usecs) in cases {
1748 let input = Interval::from_month_day_usec(months, days, usecs);
1749
1750 let mut serializer = memcomparable::Serializer::new(vec![]);
1751 input.serialize(&mut serializer).unwrap();
1752 let buf = serializer.into_inner();
1753 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1754 let actual = Interval::deserialize(&mut deserializer).unwrap();
1755
1756 assert_eq!(actual, input);
1758 }
1759
1760 let mut serializer = memcomparable::Serializer::new(vec![]);
1762 (i64::MAX, u64::MAX).serialize(&mut serializer).unwrap();
1763 let buf = serializer.into_inner();
1764 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1765 assert!(Interval::deserialize(&mut deserializer).is_err());
1766
1767 let buf = i128::MIN.to_ne_bytes();
1768 rw_catch_unwind(|| {
1769 <Interval as crate::hash::HashKeyDe>::deserialize(&DataType::Interval, &mut &buf[..])
1770 })
1771 .unwrap_err();
1772 }
1773
1774 #[test]
1775 fn test_interval_estimate_size() {
1776 let interval = Interval::MIN;
1777 assert_eq!(interval.estimated_size(), 16);
1778 }
1779
1780 #[test]
1781 fn test_iso_8601() {
1782 let iso_8601_str = "P1Y2M3DT4H5M6.789123S";
1783 let lhs = Interval::from_month_day_usec(14, 3, 14706789123);
1784 let rhs = Interval::from_iso_8601(iso_8601_str).unwrap();
1785 assert_eq!(rhs.as_iso_8601().as_str(), iso_8601_str);
1786 assert_eq!(lhs, rhs);
1787 }
1788}