(PostgreSQL 9.4.8)
我写了一个简单的SQL函数来按间隔对记录进行分组(按1天,1小时,63分钟等分组......)
CREATE OR REPLACE FUNCTION public.timestamp_bucket(startdate timestamp with time zone, step interval, datetime timestamp with time zone) RETURNS timestamptz
AS
$BODY$
SELECT startdate::timestamptz +
(
(
floor(
EXTRACT(EPOCH FROM (datetime - startdate::timestamp)) /
EXTRACT(EPOCH FROM step)
)::integer * EXTRACT(EPOCH FROM step)
) || ' seconds'
)::interval;
$BODY$ LANGUAGE sql VOLATILE COST 100;
样品:
由'1day'组成
$ select timestamp_bucket('2017-10-29 00:00:00+02'::timestamptz, '1day'::interval, '2017-10-29 00:01:02'::timestamptz);
timestamp_bucket
------------------------
2017-10-29 00:00:00+02
按“6分钟”分组
$ select timestamp_bucket('2017-09-17 00:00:00+02'::timestamptz, '6minutes'::interval, '2017-09-18 13:10:02'::timestamptz);
timestamp_bucket
------------------------
2017-09-18 13:06:00+02
但是当有夏令时它不起作用......
在法国,时区在2017年10月28日至29日的夜晚从'+02'变为'+01' 结果现在是:
select timestamp_bucket('2017-10-29 00:00:00+02'::timestamptz, '1day'::interval, '2017-10-30 09:01:02'::timestamptz);
timestamp_bucket
------------------------
2017-10-29 23:00:00+01
我可以用以下方式检查:
# select '2017-10-29 00:00:00+02'::timestamptz + '24:00:00'::interval;
?column?
------------------------
2017-10-29 23:00:00+01
但是
select '2017-10-29 00:00:00+02'::timestamptz + '1day'::interval;
?column?
------------------------
2017-10-30 00:00:00+01
好的,29日有25个小时,但有没有办法解决这个问题
timestamp_bucket('2017-10-01 00:00:00+02'::timestamptz, '1day'::interval, '2017-10-30 09:01:02'::timestamptz) = '2017-10-30 00:00:00+01'
答案 0 :(得分:0)
感谢@ michel.milezzi我发布了解决方案:
CREATE OR REPLACE FUNCTION public.timestamp_bucket(startdate timestamp with time zone, step interval, datetime timestamp with time zone) RETURNS timestamptz AS
$BODY$
SELECT (startdate::timestamp +
(
(
floor(
EXTRACT(EPOCH FROM (datetime::timestamp - startdate::timestamp)) /
EXTRACT(EPOCH FROM step)
)::integer * EXTRACT(EPOCH FROM step)
) || ' seconds'
)::interval)::timestamptz;
$BODY$ LANGUAGE sql VOLATILE COST 100;
我也尝试转换24小时'在白天,有类似的东西,但我不喜欢它:
CREATE OR REPLACE FUNCTION public.timestamp_bucket(startdate timestamp with time zone, step interval, datetime timestamp with time zone) RETURNS timestamptz
AS
$BODY$
WITH partial AS (
SELECT (
(
floor(
EXTRACT(EPOCH FROM (datetime - startdate::timestamp)) /
EXTRACT(EPOCH FROM step)
)::integer * EXTRACT(EPOCH FROM step)
) || ' seconds'
)::interval AS _interval
)
SELECT startdate::timestamptz +
CASE WHEN _interval >= '24:00:00'::interval THEN
(
EXTRACT(YEARS FROM _interval) || 'years ' ||
EXTRACT(MONTHS FROM _interval) || 'months ' ||
(EXTRACT(DAYS FROM _interval) + (EXTRACT(HOUR FROM _interval) / 24) ) || 'days ' ||
(EXTRACT(HOUR FROM _interval)::integer % 24) || 'hours ' ||
EXTRACT(MINUTES FROM _interval) || 'minutes ' ||
EXTRACT(SECONDS FROM _interval) || 'seconds ' ||
EXTRACT(MILLISECONDS FROM _interval) || 'millisecond ' ||
EXTRACT(MICROSECONDS FROM _interval) || 'microseconds'
)::interval
ELSE _interval END
FROM partial;
;
$BODY$ LANGUAGE sql VOLATILE COST 100;