Skip to content

Commit

Permalink
Stabilize date utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
syvb committed Apr 4, 2023
1 parent fda5b47 commit 11ee21b
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 27 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions extension/src/stabilization_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
117 changes: 90 additions & 27 deletions extension/src/utilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand All @@ -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,
)
Expand All @@ -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::<f64>()
.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,
)
Expand All @@ -146,40 +165,84 @@ mod tests {
.get_one::<f64>()
.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::<f64>().unwrap().unwrap();
assert!((test_val - -42f64).abs() < f64::EPSILON);
});
}

#[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::<i64>().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::<i64>()
.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::<i64>().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::<i64>()
.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::<f64>().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::<f64>()
.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::<f64>().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::<f64>()
.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::<f64>().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::<f64>()
.unwrap()
.unwrap();
assert_eq!(test_val, 967.741935483871f64);
});
}
Expand Down

0 comments on commit 11ee21b

Please sign in to comment.