1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Add date_bin function

Similar to date_trunc, but allows binning by an arbitrary interval
rather than just full units.

Author: John Naylor <john.naylor@enterprisedb.com>
Reviewed-by: David Fetter <david@fetter.org>
Reviewed-by: Isaac Morland <isaac.morland@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Artur Zakirov <zaartur@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/CACPNZCt4buQFRgy6DyjuZS-2aPDpccRkrJBmgUfwYc1KiaXYxg@mail.gmail.com
This commit is contained in:
Peter Eisentraut
2021-03-24 16:16:14 +01:00
parent 1509c6fc29
commit 49ab61f0bd
8 changed files with 402 additions and 1 deletions

View File

@ -3812,6 +3812,43 @@ timestamptz_age(PG_FUNCTION_ARGS)
*---------------------------------------------------------*/
/* timestamp_bin()
* Bin timestamp into specified interval.
*/
Datum
timestamp_bin(PG_FUNCTION_ARGS)
{
Interval *stride = PG_GETARG_INTERVAL_P(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
Timestamp origin = PG_GETARG_TIMESTAMP(2);
Timestamp result,
tm_diff,
stride_usecs,
tm_delta;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMP(timestamp);
if (TIMESTAMP_NOT_FINITE(origin))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("origin out of range")));
if (stride->month != 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("timestamps cannot be binned into intervals containing months or years")));
stride_usecs = stride->day * USECS_PER_DAY + stride->time;
tm_diff = timestamp - origin;
tm_delta = tm_diff - tm_diff % stride_usecs;;
result = origin + tm_delta;
PG_RETURN_TIMESTAMP(result);
}
/* timestamp_trunc()
* Truncate timestamp to specified units.
*/
@ -3946,6 +3983,43 @@ timestamp_trunc(PG_FUNCTION_ARGS)
PG_RETURN_TIMESTAMP(result);
}
/* timestamptz_bin()
* Bin timestamptz into specified interval using specified origin.
*/
Datum
timestamptz_bin(PG_FUNCTION_ARGS)
{
Interval *stride = PG_GETARG_INTERVAL_P(0);
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz origin = PG_GETARG_TIMESTAMPTZ(2);
TimestampTz result,
stride_usecs,
tm_diff,
tm_delta;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMPTZ(timestamp);
if (TIMESTAMP_NOT_FINITE(origin))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("origin out of range")));
if (stride->month != 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("timestamps cannot be binned into intervals containing months or years")));
stride_usecs = stride->day * USECS_PER_DAY + stride->time;
tm_diff = timestamp - origin;
tm_delta = tm_diff - tm_diff % stride_usecs;;
result = origin + tm_delta;
PG_RETURN_TIMESTAMPTZ(result);
}
/*
* Common code for timestamptz_trunc() and timestamptz_trunc_zone().
*