From 11ee21bb2c78a170e93633b12b647517e28951ed Mon Sep 17 00:00:00 2001 From: syvb Date: Tue, 4 Apr 2023 15:03:18 -0400 Subject: [PATCH] Stabilize date utilities --- Changelog.md | 1 + extension/src/stabilization_info.rs | 3 + extension/src/utilities.rs | 117 +++++++++++++++++++++------- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/Changelog.md b/Changelog.md index cbcbf1be..b13e193a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -16,6 +16,7 @@ This changelog should be updated as part of a PR if the work is worth noting (mo #### Stabilized features - [#741](https://github.com/timescale/timescaledb-toolkit/pull/741): Stabilize `approx_count_distinct` - [#748](https://github.com/timescale/timescaledb-toolkit/pull/748): Stabilize `approx_percentile_array` +- [#745](https://github.com/timescale/timescaledb-toolkit/pull/745): Stabilize date utility functions #### Other notable changes - [#743](https://github.com/timescale/timescaledb-toolkit/pull/743): Remove support for direct upgrades from toolkit versions more than 1 year old. Toolkit versions 1.4.x and 1.5.x will have to upgrade to an intermediate version before upgrading to 1.16.0. diff --git a/extension/src/stabilization_info.rs b/extension/src/stabilization_info.rs index 939fe2d4..30613fa4 100644 --- a/extension/src/stabilization_info.rs +++ b/extension/src/stabilization_info.rs @@ -32,6 +32,9 @@ crate::functions_stabilized_at! { accessorpercentilearray_in(cstring), accessorpercentilearray_out(accessorpercentilearray), arrow_uddsketch_approx_percentile_array(uddsketch,accessorpercentilearray), + days_in_month(timestamp with time zone), + month_normalize(double precision,timestamp with time zone,double precision), + to_epoch(timestamp with time zone), } "1.15.0" => { arrow_counter_interpolated_delta(countersummary,counterinterpolateddeltaaccessor), diff --git a/extension/src/utilities.rs b/extension/src/utilities.rs index b71520f4..63e2ad11 100644 --- a/extension/src/utilities.rs +++ b/extension/src/utilities.rs @@ -89,28 +89,38 @@ pub fn generate_periodic_normal_series( // Returns days in month extension_sql!( - "\n\ -CREATE FUNCTION toolkit_experimental.days_in_month(date timestamptz) RETURNS int AS $$\n\ -SELECT CAST(EXTRACT('day' FROM ($1 + interval '1 month' - $1)) as INTEGER)\n\ -$$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE;\n\ + " +CREATE FUNCTION days_in_month(date timestamptz) RETURNS int +SET search_path TO pg_catalog,pg_temp +AS $$ +SELECT CAST(EXTRACT('day' FROM ($1 + interval '1 month' - $1)) as INTEGER) +$$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; ", name = "days_in_month", ); // Normalizes metric based on reference date and days -extension_sql!("\n\ -CREATE FUNCTION toolkit_experimental.month_normalize(metric float8, reference_date timestamptz, days float8 DEFAULT 365.25/12) RETURNS float8 AS $$\n\ -SELECT metric * days / toolkit_experimental.days_in_month(reference_date)\n\ -$$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE;\n\ -", name="month_normalize",); +extension_sql!( + " +CREATE FUNCTION month_normalize(metric float8, reference_date timestamptz, days float8 DEFAULT 365.25/12) RETURNS float8 +SET search_path TO pg_catalog,pg_temp +AS $$ +SELECT metric * days / CAST(EXTRACT('day' FROM (reference_date + interval '1 month' - reference_date)) as INTEGER) +$$ LANGUAGE SQL STRICT IMMUTABLE PARALLEL SAFE; +", + name="month_normalize", +); // Convert a timestamp to a double precision unix epoch -extension_sql!("\n\ -CREATE FUNCTION toolkit_experimental.to_epoch(timestamptz) RETURNS DOUBLE PRECISION LANGUAGE SQL IMMUTABLE PARALLEL SAFE AS $$\n\ -SELECT EXTRACT(EPOCH FROM $1);\n\ -$$;\n\ +extension_sql!( + " +CREATE FUNCTION to_epoch(timestamptz) RETURNS DOUBLE PRECISION LANGUAGE SQL IMMUTABLE PARALLEL SAFE +SET search_path TO pg_catalog,pg_temp +AS $$ +SELECT EXTRACT(EPOCH FROM $1); +$$; ", -name="to_epoch", + name = "to_epoch", ); #[cfg(any(test, feature = "pg_test"))] @@ -124,7 +134,7 @@ mod tests { Spi::connect(|mut client| { let test_val = client .update( - "SELECT toolkit_experimental.to_epoch('2021-01-01 00:00:00+03'::timestamptz)", + "SELECT to_epoch('2021-01-01 00:00:00+03'::timestamptz)", None, None, ) @@ -135,9 +145,18 @@ mod tests { .unwrap(); assert!((test_val - 1609448400f64).abs() < f64::EPSILON); + let test_val = client + .update("SELECT to_epoch('epoch'::timestamptz)", None, None) + .unwrap() + .first() + .get_one::() + .unwrap() + .unwrap(); + assert!((test_val - 0f64).abs() < f64::EPSILON); + let test_val = client .update( - "SELECT toolkit_experimental.to_epoch('epoch'::timestamptz)", + "SELECT to_epoch('epoch'::timestamptz - interval '42 seconds')", None, None, ) @@ -146,12 +165,6 @@ mod tests { .get_one::() .unwrap() .unwrap(); - assert!((test_val - 0f64).abs() < f64::EPSILON); - - let test_val = client - .update("SELECT toolkit_experimental.to_epoch('epoch'::timestamptz - interval '42 seconds')", None, None) - .unwrap().first() - .get_one::().unwrap().unwrap(); assert!((test_val - -42f64).abs() < f64::EPSILON); }); } @@ -159,27 +172,77 @@ mod tests { #[pg_test] fn test_days_in_month() { Spi::connect(|mut client| { - 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::().unwrap().unwrap(); + let test_val = client + .update( + "SELECT days_in_month('2021-01-01 00:00:00+03'::timestamptz)", + None, + None, + ) + .unwrap() + .first() + .get_one::() + .unwrap() + .unwrap(); assert_eq!(test_val, 31); }); Spi::connect(|mut client| { - 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::().unwrap().unwrap(); + let test_val = client + .update( + "SELECT days_in_month('2020-02-03 00:00:00+03'::timestamptz)", + None, + None, + ) + .unwrap() + .first() + .get_one::() + .unwrap() + .unwrap(); assert_eq!(test_val, 29); }); } #[pg_test] fn test_monthly_normalize() { Spi::connect(|mut client| { - 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::().unwrap().unwrap(); + let test_val = client + .update( + "SELECT month_normalize(1000,'2021-01-01 00:00:00+03'::timestamptz)", + None, + None, + ) + .unwrap() + .first() + .get_one::() + .unwrap() + .unwrap(); assert_eq!(test_val, 981.8548387096774f64); }); Spi::connect(|mut client| { - 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::().unwrap().unwrap(); + let test_val = client + .update( + "SELECT month_normalize(1000,'2021-01-01 00:00:00+03'::timestamptz,30.5)", + None, + None, + ) + .unwrap() + .first() + .get_one::() + .unwrap() + .unwrap(); assert_eq!(test_val, 983.8709677419355f64); }); Spi::connect(|mut client| { - 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::().unwrap().unwrap(); + let test_val = client + .update( + "SELECT month_normalize(1000,'2021-01-01 00:00:00+03'::timestamptz,30)", + None, + None, + ) + .unwrap() + .first() + .get_one::() + .unwrap() + .unwrap(); assert_eq!(test_val, 967.741935483871f64); }); }