mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-17 02:53:51 +08:00
Introduce experimental time_bucket_ng() function
This patch adds time_bucket_ng() function to the experimental schema. The "ng" part stands for "next generation". Unlike current time_bucket() implementation the _ng version will support months, years and timezones. Current implementation doesn't claim to be complete. For instance, it doesn't support timezones yet. The reasons to commit it in it's current state are 1) to shorten the feedback loop 2) to start experimenting with monthly buckets are soon as possible, 3) to reduce the unnecessary work of rebasing and resolving conflicts 4) to make the work easier to the reviewers
This commit is contained in:
parent
8aaef4ae14
commit
33dfdcf5ea
@ -37,6 +37,7 @@ set(SOURCE_FILES
|
||||
ddl_triggers.sql
|
||||
bookend.sql
|
||||
time_bucket.sql
|
||||
time_bucket_ng.sql
|
||||
version.sql
|
||||
size_utils.sql
|
||||
histogram.sql
|
||||
|
29
sql/time_bucket_ng.sql
Normal file
29
sql/time_bucket_ng.sql
Normal file
@ -0,0 +1,29 @@
|
||||
-- This file and its contents are licensed under the Apache License 2.0.
|
||||
-- Please see the included NOTICE for copyright information and
|
||||
-- LICENSE-APACHE for a copy of the license.
|
||||
|
||||
-- time_bucket_ng() is an _experimental_ new version of time_bucket().
|
||||
--
|
||||
-- Unlike time_bucket(), time_bucket_ng() supports variable-sized buckets,
|
||||
-- such as months and years, and also timezones. Note that the behavior
|
||||
-- and the interface of this function are subjects to change. There could
|
||||
-- be bugs, and the implementation doesn't claim to be complete. Use at
|
||||
-- your own risk.
|
||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts DATE) RETURNS DATE
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng' LANGUAGE C STABLE PARALLEL SAFE STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts DATE, origin DATE) RETURNS DATE
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng' LANGUAGE C STABLE PARALLEL SAFE STRICT;
|
||||
|
||||
-- utility functions
|
||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts TIMESTAMP) RETURNS TIMESTAMP
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng_timestamp' LANGUAGE C STABLE PARALLEL SAFE STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts TIMESTAMP, origin TIMESTAMP) RETURNS TIMESTAMP
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng_timestamp' LANGUAGE C STABLE PARALLEL SAFE STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts TIMESTAMPTZ) RETURNS TIMESTAMPTZ
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng_timestamptz' LANGUAGE C STABLE PARALLEL SAFE STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts TIMESTAMPTZ, origin TIMESTAMPTZ) RETURNS TIMESTAMPTZ
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng_timestamptz' LANGUAGE C STABLE PARALLEL SAFE STRICT;
|
@ -48,6 +48,7 @@ set(SOURCES
|
||||
subspace_store.c
|
||||
tablespace.c
|
||||
time_bucket.c
|
||||
time_bucket_ng.c
|
||||
time_utils.c
|
||||
custom_type_cache.c
|
||||
trigger.c
|
||||
|
152
src/time_bucket_ng.c
Normal file
152
src/time_bucket_ng.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* This file and its contents are licensed under the Apache License 2.0.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-APACHE for a copy of the license.
|
||||
*/
|
||||
#include <postgres.h>
|
||||
#include <utils/date.h>
|
||||
#include <utils/datetime.h>
|
||||
#include <utils/fmgrprotos.h>
|
||||
|
||||
#include "time_bucket_ng.h"
|
||||
|
||||
TS_FUNCTION_INFO_V1(ts_time_bucket_ng);
|
||||
TS_FUNCTION_INFO_V1(ts_time_bucket_ng_timestamp);
|
||||
TS_FUNCTION_INFO_V1(ts_time_bucket_ng_timestamptz);
|
||||
|
||||
TSDLLEXPORT Datum
|
||||
ts_time_bucket_ng_timestamp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DateADT result;
|
||||
Datum interval = PG_GETARG_DATUM(0);
|
||||
DateADT ts_date = DatumGetDateADT(DirectFunctionCall1(timestamp_date, PG_GETARG_DATUM(1)));
|
||||
|
||||
if (PG_NARGS() > 2)
|
||||
{
|
||||
DateADT origin = DatumGetDateADT(DirectFunctionCall1(timestamp_date, PG_GETARG_DATUM(2)));
|
||||
result = DatumGetDateADT(DirectFunctionCall3(ts_time_bucket_ng,
|
||||
interval,
|
||||
DateADTGetDatum(ts_date),
|
||||
DateADTGetDatum(origin)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = DatumGetDateADT(
|
||||
DirectFunctionCall2(ts_time_bucket_ng, interval, DateADTGetDatum(ts_date)));
|
||||
}
|
||||
|
||||
return DirectFunctionCall1(date_timestamp, DateADTGetDatum(result));
|
||||
}
|
||||
|
||||
TSDLLEXPORT Datum
|
||||
ts_time_bucket_ng_timestamptz(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DateADT result;
|
||||
Datum interval = PG_GETARG_DATUM(0);
|
||||
DateADT ts_date = DatumGetDateADT(DirectFunctionCall1(timestamptz_date, PG_GETARG_DATUM(1)));
|
||||
|
||||
if (PG_NARGS() > 2)
|
||||
{
|
||||
DateADT origin = DatumGetDateADT(DirectFunctionCall1(timestamptz_date, PG_GETARG_DATUM(2)));
|
||||
result = DatumGetDateADT(DirectFunctionCall3(ts_time_bucket_ng,
|
||||
interval,
|
||||
DateADTGetDatum(ts_date),
|
||||
DateADTGetDatum(origin)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = DatumGetDateADT(
|
||||
DirectFunctionCall2(ts_time_bucket_ng, interval, DateADTGetDatum(ts_date)));
|
||||
}
|
||||
|
||||
return DirectFunctionCall1(date_timestamptz, DateADTGetDatum(result));
|
||||
}
|
||||
|
||||
TSDLLEXPORT Datum
|
||||
ts_time_bucket_ng(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Interval *interval = PG_GETARG_INTERVAL_P(0);
|
||||
DateADT date = PG_GETARG_DATEADT(1);
|
||||
DateADT origin_date = 0; // 2000-01-01
|
||||
int origin_year = 2000, origin_month = 1, origin_day = 1;
|
||||
int year, month, day;
|
||||
int delta, bucket_number;
|
||||
|
||||
if ((interval->time != 0) || ((interval->month != 0) && (interval->day != 0)))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("interval must be either days and weeks, or months and years")));
|
||||
}
|
||||
|
||||
if ((interval->month == 0) && (interval->day == 0))
|
||||
{
|
||||
/*
|
||||
* This will be fixed in future versions of ts_time_bucket_ng().
|
||||
* The reason why it's not yet implemented is that we want to start
|
||||
* experimenting with variable-sized buckets as soon as possible.
|
||||
* We know that fixed-sized buckets work OK and adding corresponding
|
||||
* logic will be trivial.
|
||||
*/
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("interval must be at least one day")));
|
||||
}
|
||||
|
||||
if (PG_NARGS() > 2)
|
||||
{
|
||||
origin_date = PG_GETARG_DATUM(2);
|
||||
j2date(origin_date + POSTGRES_EPOCH_JDATE, &origin_year, &origin_month, &origin_day);
|
||||
}
|
||||
|
||||
if ((origin_day != 1) && (interval->month != 0))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("origin must be the first day of the month")));
|
||||
}
|
||||
|
||||
if (DATE_NOT_FINITE(date))
|
||||
PG_RETURN_DATEADT(date);
|
||||
|
||||
if (interval->month != 0)
|
||||
{
|
||||
/* Handle months and years */
|
||||
|
||||
j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day);
|
||||
|
||||
if ((year < origin_year) || ((year == origin_year) && (month < origin_month)))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("origin must be before the given date")));
|
||||
}
|
||||
|
||||
delta = (year * 12 + month) - (origin_year * 12 + origin_month);
|
||||
bucket_number = delta / interval->month;
|
||||
year = origin_year + (bucket_number * interval->month) / 12;
|
||||
month =
|
||||
(((origin_year * 12 + (origin_month - 1)) + (bucket_number * interval->month)) % 12) +
|
||||
1;
|
||||
day = 1;
|
||||
|
||||
date = date2j(year, month, day) - POSTGRES_EPOCH_JDATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle days and weeks */
|
||||
|
||||
if (date < origin_date)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("origin must be before the given date")));
|
||||
}
|
||||
|
||||
delta = date - origin_date;
|
||||
bucket_number = delta / interval->day;
|
||||
date = bucket_number * interval->day;
|
||||
}
|
||||
|
||||
PG_RETURN_DATEADT(date);
|
||||
}
|
18
src/time_bucket_ng.h
Normal file
18
src/time_bucket_ng.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* This file and its contents are licensed under the Apache License 2.0.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-APACHE for a copy of the license.
|
||||
*/
|
||||
#ifndef TIMESCALEDB_DATE_TRUNC_H
|
||||
#define TIMESCALEDB_DATE_TRUNC_H
|
||||
|
||||
#include <postgres.h>
|
||||
#include <fmgr.h>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
extern TSDLLEXPORT Datum ts_time_bucket_ng(PG_FUNCTION_ARGS);
|
||||
extern TSDLLEXPORT Datum ts_time_bucket_ng_timestamp(PG_FUNCTION_ARGS);
|
||||
extern TSDLLEXPORT Datum ts_time_bucket_ng_timestamptz(PG_FUNCTION_ARGS);
|
||||
|
||||
#endif /* TIMESCALEDB_DATE_TRUNC_H */
|
@ -1223,6 +1223,204 @@ FROM unnest(ARRAY[
|
||||
]) AS time;
|
||||
ERROR: timestamp out of range
|
||||
\set ON_ERROR_STOP 1
|
||||
------------------------------------------------------------
|
||||
--- Test timescaledb_experimental.time_bucket_ng function --
|
||||
------------------------------------------------------------
|
||||
-- not supported functionality
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 hour', '2001-02-03' :: date) AS result;
|
||||
ERROR: interval must be either days and weeks, or months and years
|
||||
SELECT timescaledb_experimental.time_bucket_ng('0 days', '2001-02-03' :: date) AS result;
|
||||
ERROR: interval must be at least one day
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 month', '2001-02-03' :: date, origin => '2000-01-02') AS result;
|
||||
ERROR: origin must be the first day of the month
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 month', '2000-01-02' :: date, origin => '2001-01-01') AS result;
|
||||
ERROR: origin must be before the given date
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 day', '2000-01-02' :: date, origin => '2001-01-01') AS result;
|
||||
ERROR: origin must be before the given date
|
||||
\set ON_ERROR_STOP 1
|
||||
-- infinity
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', 'infinity' :: date) AS result;
|
||||
result
|
||||
----------
|
||||
infinity
|
||||
(1 row)
|
||||
|
||||
-- wrappers
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamp) AS result;
|
||||
result
|
||||
--------------------------
|
||||
Fri Jan 01 00:00:00 2021
|
||||
(1 row)
|
||||
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamptz) AS result;
|
||||
result
|
||||
------------------------------
|
||||
Fri Jan 01 00:00:00 2021 EST
|
||||
(1 row)
|
||||
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamp, origin => '2021-06-01') AS result;
|
||||
result
|
||||
--------------------------
|
||||
Tue Jun 01 00:00:00 2021
|
||||
(1 row)
|
||||
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamptz, origin => '2021-06-01') AS result;
|
||||
result
|
||||
------------------------------
|
||||
Tue Jun 01 00:00:00 2021 EDT
|
||||
(1 row)
|
||||
|
||||
-- N days / weeks buckets
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 day', d), 'YYYY-MM-DD') AS d1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 days', d), 'YYYY-MM-DD') AS d2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 days', d), 'YYYY-MM-DD') AS d3,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 week', d), 'YYYY-MM-DD') AS w1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 week 2 days', d), 'YYYY-MM-DD') AS w1d2
|
||||
FROM generate_series('2020-01-01' :: date, '2020-01-12', '1 day') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
d | d1 | d2 | d3 | w1 | w1d2
|
||||
------------+------------+------------+------------+------------+------------
|
||||
2020-01-01 | 2020-01-01 | 2019-12-31 | 2020-01-01 | 2019-12-28 | 2019-12-26
|
||||
2020-01-02 | 2020-01-02 | 2020-01-02 | 2020-01-01 | 2019-12-28 | 2019-12-26
|
||||
2020-01-03 | 2020-01-03 | 2020-01-02 | 2020-01-01 | 2019-12-28 | 2019-12-26
|
||||
2020-01-04 | 2020-01-04 | 2020-01-04 | 2020-01-04 | 2020-01-04 | 2020-01-04
|
||||
2020-01-05 | 2020-01-05 | 2020-01-04 | 2020-01-04 | 2020-01-04 | 2020-01-04
|
||||
2020-01-06 | 2020-01-06 | 2020-01-06 | 2020-01-04 | 2020-01-04 | 2020-01-04
|
||||
2020-01-07 | 2020-01-07 | 2020-01-06 | 2020-01-07 | 2020-01-04 | 2020-01-04
|
||||
2020-01-08 | 2020-01-08 | 2020-01-08 | 2020-01-07 | 2020-01-04 | 2020-01-04
|
||||
2020-01-09 | 2020-01-09 | 2020-01-08 | 2020-01-07 | 2020-01-04 | 2020-01-04
|
||||
2020-01-10 | 2020-01-10 | 2020-01-10 | 2020-01-10 | 2020-01-04 | 2020-01-04
|
||||
2020-01-11 | 2020-01-11 | 2020-01-10 | 2020-01-10 | 2020-01-11 | 2020-01-04
|
||||
2020-01-12 | 2020-01-12 | 2020-01-12 | 2020-01-10 | 2020-01-11 | 2020-01-04
|
||||
(12 rows)
|
||||
|
||||
-- N days / weeks buckets with given 'origin'
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 day', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS d1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 days', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS d2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 days', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS d3,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 week', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS w1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 week 2 days', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS w1d2
|
||||
FROM generate_series('2020-01-01' :: date, '2020-01-12', '1 day') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
d | d1 | d2 | d3 | w1 | w1d2
|
||||
------------+------------+------------+------------+------------+------------
|
||||
2020-01-01 | 2000-01-01 | 2000-01-01 | 2000-01-01 | 2000-01-01 | 2000-01-01
|
||||
2020-01-02 | 2000-01-02 | 2000-01-01 | 2000-01-01 | 2000-01-01 | 2000-01-01
|
||||
2020-01-03 | 2000-01-03 | 2000-01-03 | 2000-01-01 | 2000-01-01 | 2000-01-01
|
||||
2020-01-04 | 2000-01-04 | 2000-01-03 | 2000-01-04 | 2000-01-01 | 2000-01-01
|
||||
2020-01-05 | 2000-01-05 | 2000-01-05 | 2000-01-04 | 2000-01-01 | 2000-01-01
|
||||
2020-01-06 | 2000-01-06 | 2000-01-05 | 2000-01-04 | 2000-01-01 | 2000-01-01
|
||||
2020-01-07 | 2000-01-07 | 2000-01-07 | 2000-01-07 | 2000-01-01 | 2000-01-01
|
||||
2020-01-08 | 2000-01-08 | 2000-01-07 | 2000-01-07 | 2000-01-08 | 2000-01-01
|
||||
2020-01-09 | 2000-01-09 | 2000-01-09 | 2000-01-07 | 2000-01-08 | 2000-01-01
|
||||
2020-01-10 | 2000-01-10 | 2000-01-09 | 2000-01-10 | 2000-01-08 | 2000-01-10
|
||||
2020-01-11 | 2000-01-11 | 2000-01-11 | 2000-01-10 | 2000-01-08 | 2000-01-10
|
||||
2020-01-12 | 2000-01-12 | 2000-01-11 | 2000-01-10 | 2000-01-08 | 2000-01-10
|
||||
(12 rows)
|
||||
|
||||
-- N month buckets
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 month', d), 'YYYY-MM-DD') AS m1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 month', d), 'YYYY-MM-DD') AS m2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 month', d), 'YYYY-MM-DD') AS m3,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('4 month', d), 'YYYY-MM-DD') AS m4,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('5 month', d), 'YYYY-MM-DD') AS m5
|
||||
FROM generate_series('2020-01-01' :: date, '2020-12-01', '1 month') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
d | m1 | m2 | m3 | m4 | m5
|
||||
------------+------------+------------+------------+------------+------------
|
||||
2020-01-01 | 2020-01-01 | 2020-01-01 | 2020-01-01 | 2020-01-01 | 2020-01-01
|
||||
2020-02-01 | 2020-02-01 | 2020-01-01 | 2020-01-01 | 2020-01-01 | 2020-01-01
|
||||
2020-03-01 | 2020-03-01 | 2020-03-01 | 2020-01-01 | 2020-01-01 | 2020-01-01
|
||||
2020-04-01 | 2020-04-01 | 2020-03-01 | 2020-04-01 | 2020-01-01 | 2020-01-01
|
||||
2020-05-01 | 2020-05-01 | 2020-05-01 | 2020-04-01 | 2020-05-01 | 2020-01-01
|
||||
2020-06-01 | 2020-06-01 | 2020-05-01 | 2020-04-01 | 2020-05-01 | 2020-06-01
|
||||
2020-07-01 | 2020-07-01 | 2020-07-01 | 2020-07-01 | 2020-05-01 | 2020-06-01
|
||||
2020-08-01 | 2020-08-01 | 2020-07-01 | 2020-07-01 | 2020-05-01 | 2020-06-01
|
||||
2020-09-01 | 2020-09-01 | 2020-09-01 | 2020-07-01 | 2020-09-01 | 2020-06-01
|
||||
2020-10-01 | 2020-10-01 | 2020-09-01 | 2020-10-01 | 2020-09-01 | 2020-06-01
|
||||
2020-11-01 | 2020-11-01 | 2020-11-01 | 2020-10-01 | 2020-09-01 | 2020-11-01
|
||||
2020-12-01 | 2020-12-01 | 2020-11-01 | 2020-10-01 | 2020-09-01 | 2020-11-01
|
||||
(12 rows)
|
||||
|
||||
-- N month buckets with given 'origin'
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m3,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('4 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m4,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('5 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m5
|
||||
FROM generate_series('2020-01-01' :: date, '2020-12-01', '1 month') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
d | m1 | m2 | m3 | m4 | m5
|
||||
------------+------------+------------+------------+------------+------------
|
||||
2020-01-01 | 2019-01-01 | 2019-01-01 | 2019-11-01 | 2019-01-01 | 2019-10-01
|
||||
2020-02-01 | 2019-02-01 | 2019-01-01 | 2019-02-01 | 2019-01-01 | 2019-10-01
|
||||
2020-03-01 | 2019-03-01 | 2019-03-01 | 2019-02-01 | 2019-01-01 | 2019-03-01
|
||||
2020-04-01 | 2019-04-01 | 2019-03-01 | 2019-02-01 | 2019-01-01 | 2019-03-01
|
||||
2020-05-01 | 2020-05-01 | 2020-05-01 | 2020-05-01 | 2020-05-01 | 2019-03-01
|
||||
2020-06-01 | 2020-06-01 | 2020-05-01 | 2020-05-01 | 2020-05-01 | 2019-03-01
|
||||
2020-07-01 | 2020-07-01 | 2020-07-01 | 2020-05-01 | 2020-05-01 | 2019-03-01
|
||||
2020-08-01 | 2020-08-01 | 2020-07-01 | 2020-08-01 | 2020-05-01 | 2020-08-01
|
||||
2020-09-01 | 2020-09-01 | 2020-09-01 | 2020-08-01 | 2020-09-01 | 2020-08-01
|
||||
2020-10-01 | 2020-10-01 | 2020-09-01 | 2020-08-01 | 2020-09-01 | 2020-08-01
|
||||
2020-11-01 | 2020-11-01 | 2020-11-01 | 2020-11-01 | 2020-09-01 | 2020-08-01
|
||||
2020-12-01 | 2020-12-01 | 2020-11-01 | 2020-11-01 | 2020-09-01 | 2020-08-01
|
||||
(12 rows)
|
||||
|
||||
-- N years / N years, M month buckets
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 year', d), 'YYYY-MM-DD') AS y1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 year 6 month', d), 'YYYY-MM-DD') AS y1m6,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 years', d), 'YYYY-MM-DD') AS y2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 years 6 month', d), 'YYYY-MM-DD') AS y2m6,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 years', d), 'YYYY-MM-DD') AS y3
|
||||
FROM generate_series('2015-01-01' :: date, '2020-12-01', '6 month') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
d | y1 | y1m6 | y2 | y2m6 | y3
|
||||
------------+------------+------------+------------+------------+------------
|
||||
2015-01-01 | 2015-01-01 | 2015-01-01 | 2014-01-01 | 2015-01-01 | 2015-01-01
|
||||
2015-07-01 | 2015-01-01 | 2015-01-01 | 2014-01-01 | 2015-01-01 | 2015-01-01
|
||||
2016-01-01 | 2016-01-01 | 2015-01-01 | 2016-01-01 | 2015-01-01 | 2015-01-01
|
||||
2016-07-01 | 2016-01-01 | 2016-07-01 | 2016-01-01 | 2015-01-01 | 2015-01-01
|
||||
2017-01-01 | 2017-01-01 | 2016-07-01 | 2016-01-01 | 2015-01-01 | 2015-01-01
|
||||
2017-07-01 | 2017-01-01 | 2016-07-01 | 2016-01-01 | 2017-07-01 | 2015-01-01
|
||||
2018-01-01 | 2018-01-01 | 2018-01-01 | 2018-01-01 | 2017-07-01 | 2018-01-01
|
||||
2018-07-01 | 2018-01-01 | 2018-01-01 | 2018-01-01 | 2017-07-01 | 2018-01-01
|
||||
2019-01-01 | 2019-01-01 | 2018-01-01 | 2018-01-01 | 2017-07-01 | 2018-01-01
|
||||
2019-07-01 | 2019-01-01 | 2019-07-01 | 2018-01-01 | 2017-07-01 | 2018-01-01
|
||||
2020-01-01 | 2020-01-01 | 2019-07-01 | 2020-01-01 | 2020-01-01 | 2018-01-01
|
||||
2020-07-01 | 2020-01-01 | 2019-07-01 | 2020-01-01 | 2020-01-01 | 2018-01-01
|
||||
(12 rows)
|
||||
|
||||
-- N years / N years, M month buckets with given 'origin'
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 year', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 year 6 month', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y1m6,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 years', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 years 6 month', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y2m6,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 years', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y3
|
||||
FROM generate_series('2015-01-01' :: date, '2020-12-01', '6 month') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
d | y1 | y1m6 | y2 | y2m6 | y3
|
||||
------------+------------+------------+------------+------------+------------
|
||||
2015-01-01 | 2014-06-01 | 2013-12-01 | 2014-06-01 | 2012-12-01 | 2012-06-01
|
||||
2015-07-01 | 2015-06-01 | 2015-06-01 | 2014-06-01 | 2015-06-01 | 2015-06-01
|
||||
2016-01-01 | 2015-06-01 | 2015-06-01 | 2014-06-01 | 2015-06-01 | 2015-06-01
|
||||
2016-07-01 | 2016-06-01 | 2015-06-01 | 2016-06-01 | 2015-06-01 | 2015-06-01
|
||||
2017-01-01 | 2016-06-01 | 2016-12-01 | 2016-06-01 | 2015-06-01 | 2015-06-01
|
||||
2017-07-01 | 2017-06-01 | 2016-12-01 | 2016-06-01 | 2015-06-01 | 2015-06-01
|
||||
2018-01-01 | 2017-06-01 | 2016-12-01 | 2016-06-01 | 2017-12-01 | 2015-06-01
|
||||
2018-07-01 | 2018-06-01 | 2018-06-01 | 2018-06-01 | 2017-12-01 | 2018-06-01
|
||||
2019-01-01 | 2018-06-01 | 2018-06-01 | 2018-06-01 | 2017-12-01 | 2018-06-01
|
||||
2019-07-01 | 2019-06-01 | 2018-06-01 | 2018-06-01 | 2017-12-01 | 2018-06-01
|
||||
2020-01-01 | 2019-06-01 | 2019-12-01 | 2018-06-01 | 2017-12-01 | 2018-06-01
|
||||
2020-07-01 | 2020-06-01 | 2019-12-01 | 2020-06-01 | 2020-06-01 | 2018-06-01
|
||||
(12 rows)
|
||||
|
||||
-------------------------------------
|
||||
--- Test time input functions --
|
||||
-------------------------------------
|
||||
|
@ -598,6 +598,88 @@ FROM unnest(ARRAY[
|
||||
]) AS time;
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
------------------------------------------------------------
|
||||
--- Test timescaledb_experimental.time_bucket_ng function --
|
||||
------------------------------------------------------------
|
||||
|
||||
-- not supported functionality
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 hour', '2001-02-03' :: date) AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('0 days', '2001-02-03' :: date) AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 month', '2001-02-03' :: date, origin => '2000-01-02') AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 month', '2000-01-02' :: date, origin => '2001-01-01') AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 day', '2000-01-02' :: date, origin => '2001-01-01') AS result;
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
-- infinity
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', 'infinity' :: date) AS result;
|
||||
|
||||
-- wrappers
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamp) AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamptz) AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamp, origin => '2021-06-01') AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamptz, origin => '2021-06-01') AS result;
|
||||
|
||||
-- N days / weeks buckets
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 day', d), 'YYYY-MM-DD') AS d1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 days', d), 'YYYY-MM-DD') AS d2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 days', d), 'YYYY-MM-DD') AS d3,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 week', d), 'YYYY-MM-DD') AS w1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 week 2 days', d), 'YYYY-MM-DD') AS w1d2
|
||||
FROM generate_series('2020-01-01' :: date, '2020-01-12', '1 day') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
|
||||
-- N days / weeks buckets with given 'origin'
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 day', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS d1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 days', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS d2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 days', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS d3,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 week', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS w1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 week 2 days', d, origin => '2020-01-01'), 'YYYY-MM-DD') AS w1d2
|
||||
FROM generate_series('2020-01-01' :: date, '2020-01-12', '1 day') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
|
||||
-- N month buckets
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 month', d), 'YYYY-MM-DD') AS m1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 month', d), 'YYYY-MM-DD') AS m2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 month', d), 'YYYY-MM-DD') AS m3,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('4 month', d), 'YYYY-MM-DD') AS m4,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('5 month', d), 'YYYY-MM-DD') AS m5
|
||||
FROM generate_series('2020-01-01' :: date, '2020-12-01', '1 month') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
|
||||
-- N month buckets with given 'origin'
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m3,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('4 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m4,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('5 month', d, origin => '2019-05-01'), 'YYYY-MM-DD') AS m5
|
||||
FROM generate_series('2020-01-01' :: date, '2020-12-01', '1 month') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
|
||||
-- N years / N years, M month buckets
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 year', d), 'YYYY-MM-DD') AS y1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 year 6 month', d), 'YYYY-MM-DD') AS y1m6,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 years', d), 'YYYY-MM-DD') AS y2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 years 6 month', d), 'YYYY-MM-DD') AS y2m6,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 years', d), 'YYYY-MM-DD') AS y3
|
||||
FROM generate_series('2015-01-01' :: date, '2020-12-01', '6 month') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
|
||||
-- N years / N years, M month buckets with given 'origin'
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 year', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y1,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 year 6 month', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y1m6,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 years', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y2,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('2 years 6 month', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y2m6,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('3 years', d, origin => '2000-06-01'), 'YYYY-MM-DD') AS y3
|
||||
FROM generate_series('2015-01-01' :: date, '2020-12-01', '6 month') AS ts,
|
||||
unnest(array[ts :: date]) AS d;
|
||||
|
||||
-------------------------------------
|
||||
--- Test time input functions --
|
||||
-------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user