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 Self {
902 months: 0,
903 days: 0,
904 usecs: time.micros_of_day() as i64,
905 }
906 }
907}
908
909impl Add for Interval {
910 type Output = Self;
911
912 fn add(self, rhs: Self) -> Self {
913 let months = self.months + rhs.months;
914 let days = self.days + rhs.days;
915 let usecs = self.usecs + rhs.usecs;
916 Interval {
917 months,
918 days,
919 usecs,
920 }
921 }
922}
923
924impl CheckedNeg for Interval {
925 fn checked_neg(&self) -> Option<Self> {
926 let months = self.months.checked_neg()?;
927 let days = self.days.checked_neg()?;
928 let usecs = self.usecs.checked_neg()?;
929 Some(Interval {
930 months,
931 days,
932 usecs,
933 })
934 }
935}
936
937impl CheckedAdd for Interval {
938 fn checked_add(&self, other: &Self) -> Option<Self> {
939 let months = self.months.checked_add(other.months)?;
940 let days = self.days.checked_add(other.days)?;
941 let usecs = self.usecs.checked_add(other.usecs)?;
942 Some(Interval {
943 months,
944 days,
945 usecs,
946 })
947 }
948}
949
950impl Sub for Interval {
951 type Output = Self;
952
953 fn sub(self, rhs: Self) -> Self {
954 let months = self.months - rhs.months;
955 let days = self.days - rhs.days;
956 let usecs = self.usecs - rhs.usecs;
957 Interval {
958 months,
959 days,
960 usecs,
961 }
962 }
963}
964
965impl CheckedSub for Interval {
966 fn checked_sub(&self, other: &Self) -> Option<Self> {
967 let months = self.months.checked_sub(other.months)?;
968 let days = self.days.checked_sub(other.days)?;
969 let usecs = self.usecs.checked_sub(other.usecs)?;
970 Some(Interval {
971 months,
972 days,
973 usecs,
974 })
975 }
976}
977
978impl Zero for Interval {
979 fn zero() -> Self {
980 Self::from_month_day_usec(0, 0, 0)
981 }
982
983 fn is_zero(&self) -> bool {
984 self.months == 0 && self.days == 0 && self.usecs == 0
985 }
986}
987
988impl Neg for Interval {
989 type Output = Self;
990
991 fn neg(self) -> Self {
992 Self {
993 months: -self.months,
994 days: -self.days,
995 usecs: -self.usecs,
996 }
997 }
998}
999
1000impl ToText for crate::types::Interval {
1001 fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
1002 write!(f, "{self}")
1003 }
1004
1005 fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
1006 match ty {
1007 DataType::Interval => self.write(f),
1008 _ => unreachable!(),
1009 }
1010 }
1011}
1012
1013#[derive(thiserror::Error, Debug, thiserror_ext::Construct)]
1015pub enum IntervalParseError {
1016 #[error("Invalid interval: {0}")]
1017 Invalid(String),
1018
1019 #[error(
1020 "Invalid interval: {0}, expected format P<years>Y<months>M<days>DT<hours>H<minutes>M<seconds>S"
1021 )]
1022 InvalidIso8601(String),
1023
1024 #[error("Invalid unit: {0}")]
1025 InvalidUnit(String),
1026
1027 #[error("{0}")]
1028 Uncategorized(String),
1029}
1030
1031type ParseResult<T> = std::result::Result<T, IntervalParseError>;
1032
1033impl Interval {
1034 pub fn as_iso_8601(&self) -> String {
1035 let years = self.months / 12;
1037 let months = self.months % 12;
1038 let days = self.days;
1039 let secs_fract = (self.usecs % USECS_PER_SEC).abs();
1040 let total_secs = (self.usecs / USECS_PER_SEC).abs();
1041 let hours = total_secs / 3600;
1042 let minutes = (total_secs / 60) % 60;
1043 let seconds = total_secs % 60;
1044 let mut buf = [0u8; 7];
1045 let fract_str = if secs_fract != 0 {
1046 write!(buf.as_mut_slice(), ".{:06}", secs_fract).unwrap();
1047 std::str::from_utf8(&buf).unwrap().trim_end_matches('0')
1048 } else {
1049 ""
1050 };
1051 format!("P{years}Y{months}M{days}DT{hours}H{minutes}M{seconds}{fract_str}S")
1052 }
1053
1054 pub fn from_iso_8601(s: &str) -> ParseResult<Self> {
1062 static ISO_8601_REGEX: LazyLock<Regex> = LazyLock::new(|| {
1064 Regex::new(r"^P([0-9]+)Y([0-9]+)M([0-9]+)DT([0-9]+)H([0-9]+)M([0-9]+(?:\.[0-9]+)?)S$")
1065 .unwrap()
1066 });
1067 let f = || {
1069 let caps = ISO_8601_REGEX.captures(s)?;
1070 let years: i32 = caps[1].parse().ok()?;
1071 let months: i32 = caps[2].parse().ok()?;
1072 let days = caps[3].parse().ok()?;
1073 let hours: i64 = caps[4].parse().ok()?;
1074 let minutes: i64 = caps[5].parse().ok()?;
1075 let usecs: i64 = (Decimal::from_str_exact(&caps[6])
1077 .ok()?
1078 .checked_mul(Decimal::from_str_exact("1000000").unwrap()))?
1079 .try_into()
1080 .ok()?;
1081 Some(Interval::from_month_day_usec(
1082 years.checked_mul(12)?.checked_add(months)?,
1084 days,
1085 (hours
1087 .checked_mul(3_600)?
1088 .checked_add(minutes.checked_mul(60)?))?
1089 .checked_mul(USECS_PER_SEC)?
1090 .checked_add(usecs)?,
1091 ))
1092 };
1093 f().ok_or_else(|| IntervalParseError::invalid_iso8601(s))
1094 }
1095}
1096
1097impl Display for Interval {
1098 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1099 let years = self.months / 12;
1100 let months = self.months % 12;
1101 let days = self.days;
1102 let mut space = false;
1103 let mut following_neg = false;
1104 let mut write_i32 = |arg: i32, unit: &str| -> std::fmt::Result {
1105 if arg == 0 {
1106 return Ok(());
1107 }
1108 if space {
1109 write!(f, " ")?;
1110 }
1111 if following_neg && arg > 0 {
1112 write!(f, "+")?;
1113 }
1114 write!(f, "{arg} {unit}")?;
1115 if arg != 1 {
1116 write!(f, "s")?;
1117 }
1118 space = true;
1119 following_neg = arg < 0;
1120 Ok(())
1121 };
1122 write_i32(years, "year")?;
1123 write_i32(months, "mon")?;
1124 write_i32(days, "day")?;
1125 if self.usecs != 0 || self.months == 0 && self.days == 0 {
1126 let secs_fract = (self.usecs % USECS_PER_SEC).abs();
1128 let total_secs = (self.usecs / USECS_PER_SEC).abs();
1129 let hours = total_secs / 3600;
1130 let minutes = (total_secs / 60) % 60;
1131 let seconds = total_secs % 60;
1132
1133 if space {
1134 write!(f, " ")?;
1135 }
1136 if following_neg && self.usecs > 0 {
1137 write!(f, "+")?;
1138 } else if self.usecs < 0 {
1139 write!(f, "-")?;
1140 }
1141 write!(f, "{hours:0>2}:{minutes:0>2}:{seconds:0>2}")?;
1142 if secs_fract != 0 {
1143 let mut buf = [0u8; 7];
1144 write!(buf.as_mut_slice(), ".{:06}", secs_fract).unwrap();
1145 write!(
1146 f,
1147 "{}",
1148 std::str::from_utf8(&buf).unwrap().trim_end_matches('0')
1149 )?;
1150 }
1151 }
1152 Ok(())
1153 }
1154}
1155
1156impl ToSql for Interval {
1157 to_sql_checked!();
1158
1159 fn to_sql(
1160 &self,
1161 _: &Type,
1162 out: &mut BytesMut,
1163 ) -> std::result::Result<IsNull, Box<dyn Error + 'static + Send + Sync>> {
1164 out.put_i64(self.usecs);
1166 out.put_i32(self.days);
1167 out.put_i32(self.months);
1168 Ok(IsNull::No)
1169 }
1170
1171 fn accepts(ty: &Type) -> bool {
1172 matches!(*ty, Type::INTERVAL)
1173 }
1174}
1175
1176impl<'a> FromSql<'a> for Interval {
1177 fn from_sql(
1178 _: &Type,
1179 mut raw: &'a [u8],
1180 ) -> std::result::Result<Interval, Box<dyn Error + Sync + Send>> {
1181 let usecs = raw.read_i64::<NetworkEndian>()?;
1182 let days = raw.read_i32::<NetworkEndian>()?;
1183 let months = raw.read_i32::<NetworkEndian>()?;
1184 Ok(Interval::from_month_day_usec(months, days, usecs))
1185 }
1186
1187 fn accepts(ty: &Type) -> bool {
1188 matches!(*ty, Type::INTERVAL)
1189 }
1190}
1191
1192#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1193pub enum DateTimeField {
1194 Year,
1195 Month,
1196 Day,
1197 Hour,
1198 Minute,
1199 Second,
1200}
1201
1202impl FromStr for DateTimeField {
1203 type Err = IntervalParseError;
1204
1205 fn from_str(s: &str) -> ParseResult<Self> {
1206 match s.to_lowercase().as_str() {
1207 "years" | "year" | "yrs" | "yr" | "y" => Ok(Self::Year),
1208 "days" | "day" | "d" => Ok(Self::Day),
1209 "hours" | "hour" | "hrs" | "hr" | "h" => Ok(Self::Hour),
1210 "minutes" | "minute" | "mins" | "min" | "m" => Ok(Self::Minute),
1211 "months" | "month" | "mons" | "mon" => Ok(Self::Month),
1212 "seconds" | "second" | "secs" | "sec" | "s" => Ok(Self::Second),
1213 _ => Err(IntervalParseError::invalid_unit(s)),
1214 }
1215 }
1216}
1217
1218#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1219enum TimeStrToken {
1220 Second(F64),
1221 Num(i64),
1222 TimeUnit(DateTimeField),
1223}
1224
1225fn parse_interval(s: &str) -> ParseResult<Vec<TimeStrToken>> {
1226 let s = s.trim();
1227 let mut tokens = Vec::new();
1228 let mut num_buf = "".to_owned();
1229 let mut char_buf = "".to_owned();
1230 let mut hour_min_sec = Vec::new();
1231 for (i, c) in s.chars().enumerate() {
1232 match c {
1233 '-' | '+' => {
1234 num_buf.push(c);
1235 }
1236 '.' => {
1237 num_buf.push(c);
1238 }
1239 c if c.is_ascii_digit() => {
1240 convert_unit(&mut char_buf, &mut tokens)?;
1241 num_buf.push(c);
1242 }
1243 c if c.is_ascii_alphabetic() => {
1244 convert_digit(&mut num_buf, &mut tokens)?;
1245 char_buf.push(c);
1246 }
1247 chr if chr.is_ascii_whitespace() => {
1248 convert_unit(&mut char_buf, &mut tokens)?;
1249 if !matches!(num_buf.as_str(), "-" | "+") {
1251 convert_digit(&mut num_buf, &mut tokens)?;
1252 }
1253 }
1254 ':' => {
1255 if num_buf.is_empty() {
1257 return Err(IntervalParseError::invalid(s));
1258 }
1259 hour_min_sec.push(num_buf.clone());
1260 num_buf.clear();
1261 }
1262 _ => {
1263 return Err(IntervalParseError::uncategorized(format!(
1264 "Invalid character at offset {} in {}: {:?}. Only support digit or alphabetic now",
1265 i, s, c
1266 )));
1267 }
1268 };
1269 }
1270 if !hour_min_sec.is_empty() {
1271 if !num_buf.is_empty() {
1272 hour_min_sec.push(num_buf.clone());
1273 num_buf.clear();
1274 }
1275 } else {
1276 convert_digit(&mut num_buf, &mut tokens)?;
1277 }
1278 convert_unit(&mut char_buf, &mut tokens)?;
1279 convert_hms(&hour_min_sec, &mut tokens)
1280 .ok_or_else(|| IntervalParseError::invalid(format!("{hour_min_sec:?}")))?;
1281
1282 Ok(tokens)
1283}
1284
1285fn convert_digit(c: &mut String, t: &mut Vec<TimeStrToken>) -> ParseResult<()> {
1286 if !c.is_empty() {
1287 match c.parse::<i64>() {
1288 Ok(num) => {
1289 t.push(TimeStrToken::Num(num));
1290 }
1291 Err(_) => {
1292 return Err(IntervalParseError::invalid(c.clone()));
1293 }
1294 }
1295 c.clear();
1296 }
1297 Ok(())
1298}
1299
1300fn convert_unit(c: &mut String, t: &mut Vec<TimeStrToken>) -> ParseResult<()> {
1301 if !c.is_empty() {
1302 t.push(TimeStrToken::TimeUnit(c.parse()?));
1303 c.clear();
1304 }
1305 Ok(())
1306}
1307
1308fn convert_hms(c: &Vec<String>, t: &mut Vec<TimeStrToken>) -> Option<()> {
1315 if c.len() > 3 {
1316 return None;
1317 }
1318 let mut is_neg = false;
1319 if let Some(s) = c.first() {
1320 let v = s.parse().ok()?;
1321 is_neg = s.starts_with('-');
1322 t.push(TimeStrToken::Num(v));
1323 t.push(TimeStrToken::TimeUnit(DateTimeField::Hour))
1324 }
1325 if let Some(s) = c.get(1) {
1326 let mut v: i64 = s.parse().ok()?;
1327 if !(0..60).contains(&v) {
1328 return None;
1329 }
1330 if is_neg {
1331 v = v.checked_neg()?;
1332 }
1333 t.push(TimeStrToken::Num(v));
1334 t.push(TimeStrToken::TimeUnit(DateTimeField::Minute))
1335 }
1336 if let Some(s) = c.get(2) {
1337 let mut v: f64 = s.parse().ok()?;
1338 if !(0f64..61f64).contains(&v) {
1340 return None;
1341 }
1342 if is_neg {
1343 v = -v;
1344 }
1345 t.push(TimeStrToken::Second(v.into()));
1346 t.push(TimeStrToken::TimeUnit(DateTimeField::Second))
1347 }
1348 Some(())
1349}
1350
1351impl Interval {
1352 fn parse_sql_standard(s: &str, leading_field: DateTimeField) -> ParseResult<Self> {
1353 use DateTimeField::*;
1354 let tokens = parse_interval(s)?;
1355 if tokens.len() > 1 {
1357 return Err(IntervalParseError::invalid(s));
1358 }
1359 let num = match tokens.first() {
1360 Some(TimeStrToken::Num(num)) => *num,
1361 _ => {
1362 return Err(IntervalParseError::invalid(s));
1363 }
1364 };
1365
1366 (|| match leading_field {
1367 Year => {
1368 let months = num.checked_mul(12)?.try_into().ok()?;
1369 Some(Interval::from_month_day_usec(months, 0, 0))
1370 }
1371 Month => Some(Interval::from_month_day_usec(num.try_into().ok()?, 0, 0)),
1372 Day => Some(Interval::from_month_day_usec(0, num.try_into().ok()?, 0)),
1373 Hour => {
1374 let usecs = num.checked_mul(3600 * USECS_PER_SEC)?;
1375 Some(Interval::from_month_day_usec(0, 0, usecs))
1376 }
1377 Minute => {
1378 let usecs = num.checked_mul(60 * USECS_PER_SEC)?;
1379 Some(Interval::from_month_day_usec(0, 0, usecs))
1380 }
1381 Second => {
1382 let usecs = num.checked_mul(USECS_PER_SEC)?;
1383 Some(Interval::from_month_day_usec(0, 0, usecs))
1384 }
1385 })()
1386 .ok_or_else(|| IntervalParseError::invalid(s))
1387 }
1388
1389 fn parse_postgres(s: &str) -> ParseResult<Self> {
1390 use DateTimeField::*;
1391 let mut tokens = parse_interval(s)?;
1392 if tokens.len() % 2 != 0
1393 && let Some(TimeStrToken::Num(_)) = tokens.last()
1394 {
1395 tokens.push(TimeStrToken::TimeUnit(DateTimeField::Second));
1396 }
1397 if tokens.len() % 2 != 0 {
1398 return Err(IntervalParseError::invalid(s));
1399 }
1400 let mut token_iter = tokens.into_iter();
1401 let mut result = Interval::from_month_day_usec(0, 0, 0);
1402 while let Some(num) = token_iter.next()
1403 && let Some(interval_unit) = token_iter.next()
1404 {
1405 match (num, interval_unit) {
1406 (TimeStrToken::Num(num), TimeStrToken::TimeUnit(interval_unit)) => {
1407 result = (|| match interval_unit {
1408 Year => {
1409 let months = num.checked_mul(12)?.try_into().ok()?;
1410 Some(Interval::from_month_day_usec(months, 0, 0))
1411 }
1412 Month => Some(Interval::from_month_day_usec(num.try_into().ok()?, 0, 0)),
1413 Day => Some(Interval::from_month_day_usec(0, num.try_into().ok()?, 0)),
1414 Hour => {
1415 let usecs = num.checked_mul(3600 * USECS_PER_SEC)?;
1416 Some(Interval::from_month_day_usec(0, 0, usecs))
1417 }
1418 Minute => {
1419 let usecs = num.checked_mul(60 * USECS_PER_SEC)?;
1420 Some(Interval::from_month_day_usec(0, 0, usecs))
1421 }
1422 Second => {
1423 let usecs = num.checked_mul(USECS_PER_SEC)?;
1424 Some(Interval::from_month_day_usec(0, 0, usecs))
1425 }
1426 })()
1427 .and_then(|rhs| result.checked_add(&rhs))
1428 .ok_or_else(|| IntervalParseError::invalid(s))?;
1429 }
1430 (TimeStrToken::Second(second), TimeStrToken::TimeUnit(interval_unit)) => {
1431 result = match interval_unit {
1432 Second => {
1433 let usecs = (second.into_inner() * (USECS_PER_SEC as f64))
1436 .round_ties_even() as i64;
1437 Some(Interval::from_month_day_usec(0, 0, usecs))
1438 }
1439 _ => None,
1440 }
1441 .and_then(|rhs| result.checked_add(&rhs))
1442 .ok_or_else(|| IntervalParseError::invalid(s))?;
1443 }
1444 _ => {
1445 return Err(IntervalParseError::invalid(s));
1446 }
1447 }
1448 }
1449 Ok(result)
1450 }
1451
1452 pub fn parse_with_fields(s: &str, leading_field: Option<DateTimeField>) -> ParseResult<Self> {
1453 if let Some(leading_field) = leading_field {
1454 Self::parse_sql_standard(s, leading_field)
1455 } else {
1456 match s.as_bytes().get(0) {
1457 Some(b'P') => Self::from_iso_8601(s),
1458 _ => Self::parse_postgres(s),
1459 }
1460 }
1461 }
1462}
1463
1464impl FromStr for Interval {
1465 type Err = IntervalParseError;
1466
1467 fn from_str(s: &str) -> ParseResult<Self> {
1468 Self::parse_with_fields(s, None)
1469 }
1470}
1471
1472#[cfg(test)]
1473mod tests {
1474 use interval::test_utils::IntervalTestExt;
1475
1476 use super::*;
1477 use crate::types::ordered_float::OrderedFloat;
1478 use crate::util::panic::rw_catch_unwind;
1479
1480 #[test]
1481 fn test_parse() {
1482 let interval = "04:00:00".parse::<Interval>().unwrap();
1483 assert_eq!(interval, Interval::from_millis(4 * 3600 * 1000));
1484
1485 let interval = "1 year 2 months 3 days 00:00:01"
1486 .parse::<Interval>()
1487 .unwrap();
1488 assert_eq!(
1489 interval,
1490 Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1000)
1491 );
1492
1493 let interval = "1 year 2 months 3 days 00:00:00.001"
1494 .parse::<Interval>()
1495 .unwrap();
1496 assert_eq!(
1497 interval,
1498 Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1)
1499 );
1500
1501 let interval = "1 year 2 months 3 days 00:59:59.005"
1502 .parse::<Interval>()
1503 .unwrap();
1504 assert_eq!(
1505 interval,
1506 Interval::from_month(14)
1507 + Interval::from_days(3)
1508 + Interval::from_minutes(59)
1509 + Interval::from_millis(59000)
1510 + Interval::from_millis(5)
1511 );
1512
1513 let interval = "1 year 2 months 3 days 01".parse::<Interval>().unwrap();
1514 assert_eq!(
1515 interval,
1516 Interval::from_month(14) + Interval::from_days(3) + Interval::from_millis(1000)
1517 );
1518
1519 let interval = "1 year 2 months 3 days 1:".parse::<Interval>().unwrap();
1520 assert_eq!(
1521 interval,
1522 Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(60)
1523 );
1524
1525 let interval = "1 year 2 months 3 days 1:2".parse::<Interval>().unwrap();
1526 assert_eq!(
1527 interval,
1528 Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(62)
1529 );
1530
1531 let interval = "1 year 2 months 3 days 1:2:".parse::<Interval>().unwrap();
1532 assert_eq!(
1533 interval,
1534 Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(62)
1535 );
1536
1537 let interval = "P1Y2M3DT0H5M0S".parse::<Interval>().unwrap();
1538 assert_eq!(
1539 interval,
1540 Interval::from_month(14) + Interval::from_days(3) + Interval::from_minutes(5)
1541 );
1542 }
1543
1544 #[test]
1545 fn test_to_string() {
1546 assert_eq!(
1547 Interval::from_month_day_usec(-14, 3, (11 * 3600 + 45 * 60 + 14) * USECS_PER_SEC + 233)
1548 .to_string(),
1549 "-1 years -2 mons +3 days 11:45:14.000233"
1550 );
1551 assert_eq!(
1552 Interval::from_month_day_usec(-14, 3, 0).to_string(),
1553 "-1 years -2 mons +3 days"
1554 );
1555 assert_eq!(Interval::default().to_string(), "00:00:00");
1556 assert_eq!(
1557 Interval::from_month_day_usec(
1558 -14,
1559 3,
1560 -((11 * 3600 + 45 * 60 + 14) * USECS_PER_SEC + 233)
1561 )
1562 .to_string(),
1563 "-1 years -2 mons +3 days -11:45:14.000233"
1564 );
1565 }
1566
1567 #[test]
1568 fn test_exact_div() {
1569 let cases = [
1570 ((14, 6, 6), (14, 6, 6), Some(1)),
1571 ((0, 0, 0), (0, 0, 0), None),
1572 ((0, 0, 0), (1, 0, 0), Some(0)),
1573 ((1, 1, 1), (0, 0, 0), None),
1574 ((1, 1, 1), (1, 0, 0), None),
1575 ((10, 0, 0), (1, 0, 0), Some(10)),
1576 ((10, 0, 0), (4, 0, 0), None),
1577 ((0, 24, 0), (4, 0, 0), None),
1578 ((6, 8, 9), (3, 1, 3), None),
1579 ((6, 8, 12), (3, 4, 6), Some(2)),
1580 ];
1581
1582 for (lhs, rhs, expected) in cases {
1583 let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1584 let rhs = Interval::from_month_day_usec(rhs.0, rhs.1, rhs.2 as i64);
1585 let result = rw_catch_unwind(|| {
1586 let actual = lhs.exact_div(&rhs);
1587 assert_eq!(actual, expected);
1588 });
1589 if result.is_err() {
1590 println!("Failed on {}.exact_div({})", lhs, rhs);
1591 break;
1592 }
1593 }
1594 }
1595
1596 #[test]
1597 fn test_div_float() {
1598 let cases_int = [
1599 ((10, 8, 6), 2, Some((5, 4, 3))),
1600 ((1, 2, 33), 3, Some((0, 10, 57600000011i64))),
1601 ((1, 0, 11), 10, Some((0, 3, 1))),
1602 ((5, 6, 7), 0, None),
1603 ];
1604
1605 let cases_float = [
1606 ((10, 8, 6), 2.0f32, Some((5, 4, 3))),
1607 ((1, 2, 33), 3.0f32, Some((0, 10, 57600000011i64))),
1608 ((10, 15, 100), 2.5f32, Some((4, 6, 40))),
1609 ((5, 6, 7), 0.0f32, None),
1610 ];
1611
1612 for (lhs, rhs, expected) in cases_int {
1613 let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1614 let expected = expected.map(|x| Interval::from_month_day_usec(x.0, x.1, x.2));
1615
1616 let actual = lhs.div_float(rhs as i16);
1617 assert_eq!(actual, expected);
1618
1619 let actual = lhs.div_float(rhs);
1620 assert_eq!(actual, expected);
1621
1622 let actual = lhs.div_float(rhs as i64);
1623 assert_eq!(actual, expected);
1624 }
1625
1626 for (lhs, rhs, expected) in cases_float {
1627 let lhs = Interval::from_month_day_usec(lhs.0, lhs.1, lhs.2 as i64);
1628 let expected = expected.map(|x| Interval::from_month_day_usec(x.0, x.1, x.2));
1629
1630 let actual = lhs.div_float(OrderedFloat::<f32>(rhs));
1631 assert_eq!(actual, expected);
1632
1633 let actual = lhs.div_float(OrderedFloat::<f64>(rhs as f64));
1634 assert_eq!(actual, expected);
1635 }
1636 }
1637
1638 #[test]
1639 fn test_serialize_deserialize() {
1640 let mut serializer = memcomparable::Serializer::new(vec![]);
1641 let a = Interval::from_month_day_usec(123, 456, 789);
1642 a.serialize(&mut serializer).unwrap();
1643 let buf = serializer.into_inner();
1644 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1645 assert_eq!(Interval::deserialize(&mut deserializer).unwrap(), a);
1646 }
1647
1648 #[test]
1649 fn test_memcomparable() {
1650 let cases = [
1651 ((1, 2, 3), (4, 5, 6), Ordering::Less),
1652 ((0, 31, 0), (1, 0, 0), Ordering::Greater),
1653 ((1, 0, 0), (0, 0, USECS_PER_MONTH + 1), Ordering::Less),
1654 ((0, 1, 0), (0, 0, USECS_PER_DAY + 1), Ordering::Less),
1655 (
1656 (2, 3, 4),
1657 (1, 2, 4 + USECS_PER_DAY + USECS_PER_MONTH),
1658 Ordering::Equal,
1659 ),
1660 ];
1661
1662 for ((lhs_months, lhs_days, lhs_usecs), (rhs_months, rhs_days, rhs_usecs), order) in cases {
1663 let lhs = {
1664 let mut serializer = memcomparable::Serializer::new(vec![]);
1665 Interval::from_month_day_usec(lhs_months, lhs_days, lhs_usecs)
1666 .serialize(&mut serializer)
1667 .unwrap();
1668 serializer.into_inner()
1669 };
1670 let rhs = {
1671 let mut serializer = memcomparable::Serializer::new(vec![]);
1672 Interval::from_month_day_usec(rhs_months, rhs_days, rhs_usecs)
1673 .serialize(&mut serializer)
1674 .unwrap();
1675 serializer.into_inner()
1676 };
1677 assert_eq!(lhs.cmp(&rhs), order)
1678 }
1679 }
1680
1681 #[test]
1682 fn test_deserialize_justify() {
1683 let cases = [
1684 (
1685 (0, 0, USECS_PER_MONTH * 2 + USECS_PER_DAY * 3 + 4),
1686 Some((2, 3, 4i64, "2 mons 3 days 00:00:00.000004")),
1687 ),
1688 ((i32::MIN, i32::MIN, i64::MIN), None),
1689 ((i32::MAX, i32::MAX, i64::MAX), None),
1690 (
1691 (0, i32::MIN, i64::MIN),
1692 Some((
1693 -75141187,
1694 -29,
1695 -14454775808,
1696 "-6261765 years -7 mons -29 days -04:00:54.775808",
1697 )),
1698 ),
1699 (
1700 (i32::MIN, -60, i64::MAX),
1701 Some((
1702 -2143925250,
1703 -8,
1704 -71945224193,
1705 "-178660437 years -6 mons -8 days -19:59:05.224193",
1706 )),
1707 ),
1708 ];
1709 for ((lhs_months, lhs_days, lhs_usecs), rhs) in cases {
1710 let input = Interval::from_month_day_usec(lhs_months, lhs_days, lhs_usecs);
1711 let actual_deserialize = IntervalCmpValue::from(input).as_justified();
1712
1713 match rhs {
1714 None => {
1715 assert_eq!(actual_deserialize, None);
1716 }
1717 Some((rhs_months, rhs_days, rhs_usecs, rhs_str)) => {
1718 assert_eq!(actual_deserialize.unwrap().months(), rhs_months);
1720 assert_eq!(actual_deserialize.unwrap().days(), rhs_days);
1721 assert_eq!(actual_deserialize.unwrap().usecs(), rhs_usecs);
1722 assert_eq!(actual_deserialize.unwrap().to_string(), rhs_str);
1723 }
1724 }
1725 }
1726
1727 let input = Interval::from_month_day_usec(i32::MIN, -30, 1);
1729 let actual_deserialize = IntervalCmpValue::from(input).as_justified();
1730 assert_eq!(actual_deserialize.unwrap().months(), i32::MIN);
1732 assert_eq!(actual_deserialize.unwrap().days(), -29);
1733 assert_eq!(actual_deserialize.unwrap().usecs(), -USECS_PER_DAY + 1);
1734 }
1735
1736 #[test]
1737 fn test_deserialize_alternate() {
1738 let cases = [
1739 (0, 0, USECS_PER_MONTH * 2 + USECS_PER_DAY * 3 + 4),
1740 (i32::MIN, i32::MIN, i64::MIN),
1741 (i32::MAX, i32::MAX, i64::MAX),
1742 (0, i32::MIN, i64::MIN),
1743 (i32::MIN, -60, i64::MAX),
1744 ];
1745 for (months, days, usecs) in cases {
1746 let input = Interval::from_month_day_usec(months, days, usecs);
1747
1748 let mut serializer = memcomparable::Serializer::new(vec![]);
1749 input.serialize(&mut serializer).unwrap();
1750 let buf = serializer.into_inner();
1751 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1752 let actual = Interval::deserialize(&mut deserializer).unwrap();
1753
1754 assert_eq!(actual, input);
1756 }
1757
1758 let mut serializer = memcomparable::Serializer::new(vec![]);
1760 (i64::MAX, u64::MAX).serialize(&mut serializer).unwrap();
1761 let buf = serializer.into_inner();
1762 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
1763 assert!(Interval::deserialize(&mut deserializer).is_err());
1764
1765 let buf = i128::MIN.to_ne_bytes();
1766 rw_catch_unwind(|| {
1767 <Interval as crate::hash::HashKeyDe>::deserialize(&DataType::Interval, &mut &buf[..])
1768 })
1769 .unwrap_err();
1770 }
1771
1772 #[test]
1773 fn test_interval_estimate_size() {
1774 let interval = Interval::MIN;
1775 assert_eq!(interval.estimated_size(), 16);
1776 }
1777
1778 #[test]
1779 fn test_iso_8601() {
1780 let iso_8601_str = "P1Y2M3DT4H5M6.789123S";
1781 let lhs = Interval::from_month_day_usec(14, 3, 14706789123);
1782 let rhs = Interval::from_iso_8601(iso_8601_str).unwrap();
1783 assert_eq!(rhs.as_iso_8601().as_str(), iso_8601_str);
1784 assert_eq!(lhs, rhs);
1785 }
1786}