mz_expr/scalar/func/impls/
mz_timestamp.rs1use chrono::{DateTime, NaiveDate, NaiveDateTime, Utc};
11use mz_expr_derive::sqlfunc;
12use mz_ore::result::ResultExt;
13use mz_repr::adt::date::Date;
14use mz_repr::adt::numeric::Numeric;
15use mz_repr::adt::timestamp::CheckedTimestamp;
16use mz_repr::{Timestamp, strconv};
17
18use crate::EvalError;
19
20#[sqlfunc(
26 sqlname = "mz_timestamp_to_text",
27 preserves_uniqueness = true,
28 inverse = to_unary!(super::CastStringToMzTimestamp)
29)]
30fn cast_mz_timestamp_to_string(a: Timestamp) -> String {
31 let mut buf = String::new();
32 strconv::format_mz_timestamp(&mut buf, a);
33 buf
34}
35
36#[sqlfunc(
37 sqlname = "text_to_mz_timestamp",
38 preserves_uniqueness = false,
39 inverse = to_unary!(super::CastMzTimestampToString)
40)]
41fn cast_string_to_mz_timestamp(a: String) -> Result<Timestamp, EvalError> {
42 strconv::parse_mz_timestamp(&a).err_into()
43}
44
45#[sqlfunc(
46 sqlname = "numeric_to_mz_timestamp",
47 preserves_uniqueness = true,
48 is_monotone = true
49)]
50fn cast_numeric_to_mz_timestamp(a: Numeric) -> Result<Timestamp, EvalError> {
51 a.try_into()
53 .map_err(|_| EvalError::MzTimestampOutOfRange(a.to_string().into()))
54}
55
56#[sqlfunc(
57 sqlname = "uint8_to_mz_timestamp",
58 preserves_uniqueness = true,
59 is_monotone = true
60)]
61fn cast_uint64_to_mz_timestamp(a: u64) -> Timestamp {
62 a.into()
63}
64
65#[sqlfunc(
66 sqlname = "uint4_to_mz_timestamp",
67 preserves_uniqueness = true,
68 is_monotone = true
69)]
70fn cast_uint32_to_mz_timestamp(a: u32) -> Timestamp {
71 u64::from(a).into()
72}
73
74#[sqlfunc(
75 sqlname = "bigint_to_mz_timestamp",
76 preserves_uniqueness = true,
77 is_monotone = true
78)]
79fn cast_int64_to_mz_timestamp(a: i64) -> Result<Timestamp, EvalError> {
80 a.try_into()
81 .map_err(|_| EvalError::MzTimestampOutOfRange(a.to_string().into()))
82}
83
84#[sqlfunc(
85 sqlname = "integer_to_mz_timestamp",
86 preserves_uniqueness = true,
87 is_monotone = true
88)]
89fn cast_int32_to_mz_timestamp(a: i32) -> Result<Timestamp, EvalError> {
90 i64::from(a)
91 .try_into()
92 .map_err(|_| EvalError::MzTimestampOutOfRange(a.to_string().into()))
93}
94
95#[sqlfunc(sqlname = "timestamp_tz_to_mz_timestamp", is_monotone = true)]
96fn cast_timestamp_tz_to_mz_timestamp(
97 a: CheckedTimestamp<DateTime<Utc>>,
98) -> Result<Timestamp, EvalError> {
99 a.timestamp_millis()
100 .try_into()
101 .map_err(|_| EvalError::MzTimestampOutOfRange(a.to_string().into()))
102}
103
104#[sqlfunc(sqlname = "timestamp_to_mz_timestamp", is_monotone = true)]
105fn cast_timestamp_to_mz_timestamp(
106 a: CheckedTimestamp<NaiveDateTime>,
107) -> Result<Timestamp, EvalError> {
108 a.and_utc()
109 .timestamp_millis()
110 .try_into()
111 .map_err(|_| EvalError::MzTimestampOutOfRange(a.to_string().into()))
112}
113
114#[sqlfunc(
115 sqlname = "date_to_mz_timestamp",
116 preserves_uniqueness = true,
117 is_monotone = true
118)]
119fn cast_date_to_mz_timestamp(a: Date) -> Result<Timestamp, EvalError> {
120 let ts = CheckedTimestamp::try_from(NaiveDate::from(a).and_hms_opt(0, 0, 0).unwrap())?;
121 ts.and_utc()
122 .timestamp_millis()
123 .try_into()
124 .map_err(|_| EvalError::MzTimestampOutOfRange(a.to_string().into()))
125}
126
127#[sqlfunc(
128 sqlname = "mz_timestamp_to_timestamp",
129 preserves_uniqueness = true,
130 inverse = to_unary!(super::CastTimestampToMzTimestamp)
131)]
132fn cast_mz_timestamp_to_timestamp(
133 a: Timestamp,
134) -> Result<CheckedTimestamp<NaiveDateTime>, EvalError> {
135 let ms: i64 = a.try_into().map_err(|_| EvalError::TimestampOutOfRange)?;
136 let ct = DateTime::from_timestamp_millis(ms).and_then(|dt| {
137 let ct: Option<CheckedTimestamp<NaiveDateTime>> = dt.naive_utc().try_into().ok();
138 ct
139 });
140 ct.ok_or(EvalError::TimestampOutOfRange)
141}
142
143#[sqlfunc(
144 sqlname = "mz_timestamp_to_timestamp_tz",
145 preserves_uniqueness = true,
146 inverse = to_unary!(super::CastTimestampTzToMzTimestamp)
147)]
148fn cast_mz_timestamp_to_timestamp_tz(
149 a: Timestamp,
150) -> Result<CheckedTimestamp<DateTime<Utc>>, EvalError> {
151 let ms: i64 = a.try_into().map_err(|_| EvalError::TimestampOutOfRange)?;
152 let ct = DateTime::from_timestamp_millis(ms).and_then(|dt| {
153 let ct: Option<CheckedTimestamp<DateTime<Utc>>> = dt.try_into().ok();
154 ct
155 });
156 ct.ok_or(EvalError::TimestampOutOfRange)
157}
158
159#[sqlfunc(
160 sqlname = "step_mz_timestamp",
161 preserves_uniqueness = true,
162 is_monotone = true
163)]
164fn step_mz_timestamp(a: Timestamp) -> Result<Timestamp, EvalError> {
165 a.checked_add(1).ok_or(EvalError::MzTimestampStepOverflow)
166}