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