mz_expr/scalar/func/impls/
interval.rs1use chrono::NaiveTime;
11use mz_ore::cast::CastLossy;
12use mz_repr::adt::interval::{Interval, USECS_PER_DAY};
13use mz_repr::strconv;
14use num::traits::CheckedNeg;
15
16use crate::EvalError;
17
18sqlfunc!(
19 #[sqlname = "interval_to_text"]
20 #[preserves_uniqueness = true]
21 #[inverse = to_unary!(super::CastStringToInterval)]
22 fn cast_interval_to_string(a: Interval) -> String {
23 let mut buf = String::new();
24 strconv::format_interval(&mut buf, a);
25 buf
26 }
27);
28
29sqlfunc!(
30 #[sqlname = "interval_to_time"]
31 #[preserves_uniqueness = false]
32 #[inverse = to_unary!(super::CastTimeToInterval)]
33 fn cast_interval_to_time(i: Interval) -> NaiveTime {
34 let mut result = i.micros % *USECS_PER_DAY;
37 if result < 0 {
38 result += *USECS_PER_DAY;
39 }
40
41 let i = Interval::new(0, 0, result);
42
43 let hours: u32 = i
44 .hours()
45 .try_into()
46 .expect("interval is positive and hours() returns a value in the range [-24, 24]");
47 let minutes: u32 = i
48 .minutes()
49 .try_into()
50 .expect("interval is positive and minutes() returns a value in the range [-60, 60]");
51 let seconds: u32 = i64::cast_lossy(i.seconds::<f64>()).try_into().expect(
52 "interval is positive and seconds() returns a value in the range [-60.0, 60.0]",
53 );
54 let nanoseconds: u32 =
55 i.nanoseconds().try_into().expect(
56 "interval is positive and nanoseconds() returns a value in the range [-1_000_000_000, 1_000_000_000]",
57 );
58
59 NaiveTime::from_hms_nano_opt(hours, minutes, seconds, nanoseconds).unwrap()
60 }
61);
62
63sqlfunc!(
64 #[sqlname = "-"]
65 #[preserves_uniqueness = true]
66 #[inverse = to_unary!(super::NegInterval)]
67 fn neg_interval(i: Interval) -> Result<Interval, EvalError> {
68 i.checked_neg()
69 .ok_or_else(|| EvalError::IntervalOutOfRange(i.to_string().into()))
70 }
71);
72
73sqlfunc!(
74 #[sqlname = "justify_days"]
75 fn justify_days(i: Interval) -> Result<Interval, EvalError> {
76 i.justify_days()
77 .map_err(|_| EvalError::IntervalOutOfRange(i.to_string().into()))
78 }
79);
80
81sqlfunc!(
82 #[sqlname = "justify_hours"]
83 fn justify_hours(i: Interval) -> Result<Interval, EvalError> {
84 i.justify_hours()
85 .map_err(|_| EvalError::IntervalOutOfRange(i.to_string().into()))
86 }
87);
88
89sqlfunc!(
90 #[sqlname = "justify_interval"]
91 fn justify_interval(i: Interval) -> Result<Interval, EvalError> {
92 i.justify_interval()
93 .map_err(|_| EvalError::IntervalOutOfRange(i.to_string().into()))
94 }
95);