Skip to content

Commit d0a5235

Browse files
committed
Stabilize date utilities
1 parent be98c0a commit d0a5235

File tree

2 files changed

+93
-27
lines changed

2 files changed

+93
-27
lines changed

extension/src/stabilization_info.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ crate::functions_stabilized_at! {
1414
"1.16.0" => {
1515
approx_count_distinct(anyelement),
1616
approx_count_distinct_trans(internal,anyelement),
17+
days_in_month(timestamp with time zone),
18+
month_normalize(double precision,timestamp with time zone,double precision),
19+
to_epoch(timestamp with time zone),
1720
}
1821
"1.15.0" => {
1922
arrow_counter_interpolated_delta(countersummary,counterinterpolateddeltaaccessor),

extension/src/utilities.rs

Lines changed: 90 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -89,28 +89,38 @@ pub fn generate_periodic_normal_series(
8989

9090
// Returns days in month
9191
extension_sql!(
92-
"\n\
93-
CREATE FUNCTION toolkit_experimental.days_in_month(date timestamptz) RETURNS int AS $$\n\
94-
SELECT CAST(EXTRACT('day' FROM ($1 + interval '1 month' - $1)) as INTEGER)\n\
95-
$$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE;\n\
92+
"
93+
CREATE FUNCTION days_in_month(date timestamptz) RETURNS int
94+
SET search_path TO pg_catalog,pg_temp
95+
AS $$
96+
SELECT CAST(EXTRACT('day' FROM ($1 + interval '1 month' - $1)) as INTEGER)
97+
$$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE;
9698
",
9799
name = "days_in_month",
98100
);
99101

100102
// Normalizes metric based on reference date and days
101-
extension_sql!("\n\
102-
CREATE FUNCTION toolkit_experimental.month_normalize(metric float8, reference_date timestamptz, days float8 DEFAULT 365.25/12) RETURNS float8 AS $$\n\
103-
SELECT metric * days / toolkit_experimental.days_in_month(reference_date)\n\
104-
$$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE;\n\
105-
", name="month_normalize",);
103+
extension_sql!(
104+
"
105+
CREATE FUNCTION month_normalize(metric float8, reference_date timestamptz, days float8 DEFAULT 365.25/12) RETURNS float8
106+
SET search_path TO pg_catalog,pg_temp
107+
AS $$
108+
SELECT metric * days / CAST(EXTRACT('day' FROM (reference_date + interval '1 month' - reference_date)) as INTEGER)
109+
$$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE;
110+
",
111+
name="month_normalize",
112+
);
106113

107114
// Convert a timestamp to a double precision unix epoch
108-
extension_sql!("\n\
109-
CREATE FUNCTION toolkit_experimental.to_epoch(timestamptz) RETURNS DOUBLE PRECISION LANGUAGE SQL IMMUTABLE PARALLEL SAFE AS $$\n\
110-
SELECT EXTRACT(EPOCH FROM $1);\n\
111-
$$;\n\
115+
extension_sql!(
116+
"
117+
CREATE FUNCTION to_epoch(timestamptz) RETURNS DOUBLE PRECISION LANGUAGE SQL IMMUTABLE PARALLEL SAFE
118+
SET search_path TO pg_catalog,pg_temp
119+
AS $$
120+
SELECT EXTRACT(EPOCH FROM $1);
121+
$$;
112122
",
113-
name="to_epoch",
123+
name = "to_epoch",
114124
);
115125

116126
#[cfg(any(test, feature = "pg_test"))]
@@ -124,7 +134,7 @@ mod tests {
124134
Spi::connect(|mut client| {
125135
let test_val = client
126136
.update(
127-
"SELECT toolkit_experimental.to_epoch('2021-01-01 00:00:00+03'::timestamptz)",
137+
"SELECT to_epoch('2021-01-01 00:00:00+03'::timestamptz)",
128138
None,
129139
None,
130140
)
@@ -135,9 +145,18 @@ mod tests {
135145
.unwrap();
136146
assert!((test_val - 1609448400f64).abs() < f64::EPSILON);
137147

148+
let test_val = client
149+
.update("SELECT to_epoch('epoch'::timestamptz)", None, None)
150+
.unwrap()
151+
.first()
152+
.get_one::<f64>()
153+
.unwrap()
154+
.unwrap();
155+
assert!((test_val - 0f64).abs() < f64::EPSILON);
156+
138157
let test_val = client
139158
.update(
140-
"SELECT toolkit_experimental.to_epoch('epoch'::timestamptz)",
159+
"SELECT to_epoch('epoch'::timestamptz - interval '42 seconds')",
141160
None,
142161
None,
143162
)
@@ -146,40 +165,84 @@ mod tests {
146165
.get_one::<f64>()
147166
.unwrap()
148167
.unwrap();
149-
assert!((test_val - 0f64).abs() < f64::EPSILON);
150-
151-
let test_val = client
152-
.update("SELECT toolkit_experimental.to_epoch('epoch'::timestamptz - interval '42 seconds')", None, None)
153-
.unwrap().first()
154-
.get_one::<f64>().unwrap().unwrap();
155168
assert!((test_val - -42f64).abs() < f64::EPSILON);
156169
});
157170
}
158171

159172
#[pg_test]
160173
fn test_days_in_month() {
161174
Spi::connect(|mut client| {
162-
let test_val = client.update("SELECT toolkit_experimental.days_in_month('2021-01-01 00:00:00+03'::timestamptz)",None,None,).unwrap().first().get_one::<i64>().unwrap().unwrap();
175+
let test_val = client
176+
.update(
177+
"SELECT days_in_month('2021-01-01 00:00:00+03'::timestamptz)",
178+
None,
179+
None,
180+
)
181+
.unwrap()
182+
.first()
183+
.get_one::<i64>()
184+
.unwrap()
185+
.unwrap();
163186
assert_eq!(test_val, 31);
164187
});
165188

166189
Spi::connect(|mut client| {
167-
let test_val = client.update("SELECT toolkit_experimental.days_in_month('2020-02-03 00:00:00+03'::timestamptz)",None,None,).unwrap().first().get_one::<i64>().unwrap().unwrap();
190+
let test_val = client
191+
.update(
192+
"SELECT days_in_month('2020-02-03 00:00:00+03'::timestamptz)",
193+
None,
194+
None,
195+
)
196+
.unwrap()
197+
.first()
198+
.get_one::<i64>()
199+
.unwrap()
200+
.unwrap();
168201
assert_eq!(test_val, 29);
169202
});
170203
}
171204
#[pg_test]
172205
fn test_monthly_normalize() {
173206
Spi::connect(|mut client| {
174-
let test_val = client.update("SELECT toolkit_experimental.month_normalize(1000,'2021-01-01 00:00:00+03'::timestamptz)",None,None,).unwrap().first().get_one::<f64>().unwrap().unwrap();
207+
let test_val = client
208+
.update(
209+
"SELECT month_normalize(1000,'2021-01-01 00:00:00+03'::timestamptz)",
210+
None,
211+
None,
212+
)
213+
.unwrap()
214+
.first()
215+
.get_one::<f64>()
216+
.unwrap()
217+
.unwrap();
175218
assert_eq!(test_val, 981.8548387096774f64);
176219
});
177220
Spi::connect(|mut client| {
178-
let test_val = client.update("SELECT toolkit_experimental.month_normalize(1000,'2021-01-01 00:00:00+03'::timestamptz,30.5)",None,None,).unwrap().first().get_one::<f64>().unwrap().unwrap();
221+
let test_val = client
222+
.update(
223+
"SELECT month_normalize(1000,'2021-01-01 00:00:00+03'::timestamptz,30.5)",
224+
None,
225+
None,
226+
)
227+
.unwrap()
228+
.first()
229+
.get_one::<f64>()
230+
.unwrap()
231+
.unwrap();
179232
assert_eq!(test_val, 983.8709677419355f64);
180233
});
181234
Spi::connect(|mut client| {
182-
let test_val = client.update("SELECT toolkit_experimental.month_normalize(1000,'2021-01-01 00:00:00+03'::timestamptz,30)",None,None,).unwrap().first().get_one::<f64>().unwrap().unwrap();
235+
let test_val = client
236+
.update(
237+
"SELECT month_normalize(1000,'2021-01-01 00:00:00+03'::timestamptz,30)",
238+
None,
239+
None,
240+
)
241+
.unwrap()
242+
.first()
243+
.get_one::<f64>()
244+
.unwrap()
245+
.unwrap();
183246
assert_eq!(test_val, 967.741935483871f64);
184247
});
185248
}

0 commit comments

Comments
 (0)