我正在尝试在 DATE_TRUNC 函数中自定义时间范围,而不是典型的
DATE_TRUNC('hour', user.created_at)
理想情况下,我想要类似的东西
DATE_TRUNC('3 hours', user.created_at)
但是这当然不是有效的时区单位,所以我收到类似
的错误ERROR: timestamp with time zone units "3 hour" not recognized
********** Error **********
ERROR: timestamp with time zone units "3 hour" not recognized
SQL state: 22023
我知道我可以修改 CASE 语句,例如
'2019-7-26'::DATE + {{number}} * (CASE WHEN 'hour' THEN '1 hour'::INTERVAL
WHEN 'minute' THEN '1 minute'::INTERVAL
WHEN 'second' THEN '1 second'::INTERVAL
END)
但我不想改变时间戳,而且我不知道如何修改它来实现我上面想要的。
有点痛苦,但你可以这样做:
select (date_trunc('day', user.created_at) +
floor(extract(hour from user.created_at) / 3) * interval '3 hour'
)
你可以这样做:
date_trunc('hour', user.created_at) + interval '3 hour'
你想得到什么结果?你说你不想改变时间戳,那么你想用“3小时”返回什么?
我不确定我完全理解你的“DATE_TRUNC('3小时',user.created_at)”,但它看起来像是从午夜返回一些间隔。所以我将继续这个假设。
内置的 date_trunc 函数定义为采用 2 个参数,文本和时间戳(实际上为带时区的时间戳和不带时区的时间戳重载)。您可以扩展此重载概念,并使用间隔而不是文本来重载。” 所以
create or replace function date_trunc (intv interval, ts timestamp without time zone)
returns timestamp without time zone
language sql immutable leakproof
as $$
select date_trunc('day', ts) + intv;
$$;
create or replace function date_trunc (intv interval, ts timestamp with time zone)
returns timestamp with time zone
language sql immutable leakproof
as $$
select date_trunc('day', ts) + intv;
$$;
-- Test
select date_trunc('3 hours'::interval, now()) with_ts
, date_trunc('3 hours'::interval, now()::timestamp without time zone) without_ts;
但是我不喜欢重新定义内置函数,当以后出现问题时会导致很多混乱。因此,我不会重载内置函数,而是创建一个新的用户定义函数名称;例如 Date_Trunc_To_Interval。但你可以自由地变得危险。
从PG 14开始,就可以使用
date_bin
:
-- Params: interval, datetime, source
SELECT date_bin('3 hours', user.created_at, date_trunc('day', user.created_at))
实际来源确保在 00、03、06、...、18、21 小时对齐。
文档:https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-BIN