Gaj*_*jus 5 postgresql datetime interval date-math
例子:
INTERVAL '5 minute'
,则所需输出为 2018-05-17 22:50:00。INTERVAL '10 minute'
,则所需输出为 2018-05-17 22:50:00。INTERVAL '1 hour'
,则所需的输出为 2018-05-17 23:00:00。INTERVAL '1 day'
,那么期望的输出是 2018-05-18 00:00:00。假设数据类型timestamp
. 一些细节是不同的date
或timestamptz
。
任何时间间隔的通用解决方案都可以根据纪元值和整数除法进行截断。涵盖您的所有示例。
你的任务的特殊难度:你想要天花板,而不是地板(这更常见)。小心使用下限和上限以避免角落案例错误:您不想增加确切的地板值。(或者我假设。)
对于内置的常见时间间隔date_trunc()
(例如1 hour
和1 day
在您的示例中),您可以使用快捷方式。天数的定义取决于会话的时区设置timestamptz
(但不与timestamp
)。
一个自然的选择是使用ceil()
. 在我的测试中有点慢,但更干净。
Run Code Online (Sandbox Code Playgroud)-- short demo WITH t(ts) AS (SELECT timestamp '2018-05-17 22:45:30') -- your input timestamp SELECT t2.* FROM (SELECT *, ts - interval '1 microsecond' AS ts1 FROM t) t1 -- subtract min time interval 1 µs , LATERAL ( VALUES ('input timestamp' , ts) , ('5 min' , to_timestamp(trunc(extract(epoch FROM ts1))::int / 300 * 300 + 300) AT TIME ZONE 'UTC') , ('10 min', to_timestamp(ceil (extract(epoch FROM ts)/ 600) * 600) AT TIME ZONE 'UTC') -- based on unaltered ts! , ('hour' , date_trunc('hour', ts1) + interval '1 hour') , ('day' , date_trunc('day' , ts1) + interval '1 day') ) t2(interval, ceil_ts);
间隔| ceil_ts :-------------- | :------------------ 输入时间戳 | 2018-05-17 22:45:30 5 分钟 | 2018-05-17 22:50:00 10 分钟 | 2018-05-17 22:50:00 小时 | 2018-05-17 23:00:00 日 | 2018-05-18 00:00:00
'5 min'计算的“技巧”是在截断之前减去1 µs的最小时间间隔,然后添加相应的时间间隔以有效获得上限。EXTRACT()
返回时间戳中的秒数,一个double precision
小数位数到微秒的数字。我们需要,trunc()
因为普通的 cast tointeger
会四舍五入,而我们需要truncate。
这样我们就可以避免增加恰好落在上限的时间戳。不过,它有点脏,因为最小时间间隔是当前 Postgres 版本的实现细节。非常不可能改变,虽然。有关的:
在'10分钟的计算是简单的ceil()
,我们并不需要减去1微秒转移界限。清洁工。但ceil()
在我的测试中稍微贵一些。
Run Code Online (Sandbox Code Playgroud)WITH t(id, ts) AS ( VALUES (1, timestamp '2018-05-17 22:45:30') -- your input timestamps here , (2, timestamp '2018-05-20 00:00:00') , (3, timestamp '2018-05-20 00:00:00.000001') ) SELECT * FROM (SELECT *, ts - interval '1 microsecond' AS ts1 FROM t) t1 -- subtract min time interval 1 µs , LATERAL ( VALUES ('input timestamp' , ts) , ('5 min' , to_timestamp(trunc(extract(epoch FROM ts1))::int / 300 * 300 + 300) AT TIME ZONE 'UTC') , ('10 min' , to_timestamp(ceil (extract(epoch FROM ts)/ 600) * 600) AT TIME ZONE 'UTC') -- based on unaltered ts! , ('hour' , date_trunc('hour', ts1) + interval '1 hour') , ('day' , date_trunc('day' , ts1) + interval '1 day') , ('alt_day', ts1::date + 1) ) t2(interval, ceil_ts) ORDER BY id;
身份证 | ts | ts1 | 间隔| ceil_ts -: | :------------------------- | :------------------------- | :-------------- | :------------------------- 1 | 2018-05-17 22:45:30 | 2018-05-17 22:45:29.999999 | 输入时间戳 | 2018-05-17 22:45:30 1 | 2018-05-17 22:45:30 | 2018-05-17 22:45:29.999999 | 5 分钟 | 2018-05-17 22:50:00 1 | 2018-05-17 22:45:30 | 2018-05-17 22:45:29.999999 | 10 分钟 | 2018-05-17 22:50:00 1 | 2018-05-17 22:45:30 | 2018-05-17 22:45:29.999999 | 小时 | 2018-05-17 23:00:00 1 | 2018-05-17 22:45:30 | 2018-05-17 22:45:29.999999 | 日 | 2018-05-18 00:00:00 1 | 2018-05-17 22:45:30 | 2018-05-17 22:45:29.999999 | alt_day | 2018-05-18 00:00:00 2 | 2018-05-20 00:00:00 | 2018-05-19 23:59:59.999999 | 输入时间戳 | 2018-05-20 00:00:00 2 | 2018-05-20 00:00:00 | 2018-05-19 23:59:59.999999 | 5 分钟 | 2018-05-20 00:00:00 2 | 2018-05-20 00:00:00 | 2018-05-19 23:59:59.999999 | 10 分钟 | 2018-05-20 00:00:00 2 | 2018-05-20 00:00:00 | 2018-05-19 23:59:59.999999 | 小时 | 2018-05-20 00:00:00 2 | 2018-05-20 00:00:00 | 2018-05-19 23:59:59.999999 | 日 | 2018-05-20 00:00:00 2 | 2018-05-20 00:00:00 | 2018-05-19 23:59:59.999999 | alt_day | 2018-05-20 00:00:00 3 | 2018-05-20 00:00:00.000001 | 2018-05-20 00:00:00 | 输入时间戳 | 2018-05-20 00:00:00.000001 3 | 2018-05-20 00:00:00.000001 | 2018-05-20 00:00:00 | 5 分钟 | 2018-05-20 00:05:00 3 | 2018-05-20 00:00:00.000001 | 2018-05-20 00:00:00 | 10 分钟 | 2018-05-20 00:10:00 3 | 2018-05-20 00:00:00.000001 | 2018-05-20 00:00:00 | 小时 | 2018-05-20 01:00:00 3 | 2018-05-20 00:00:00.000001 | 2018-05-20 00:00:00 | 日 | 2018-05-21 00:00:00 3 | 2018-05-20 00:00:00.000001 | 2018-05-20 00:00:00 | alt_day | 2018-05-21 00:00:00
db<>在这里摆弄
我添加了一个全天的替代快捷方式:ts1::date + 1
. 演员要date
截断到整整一天,我们可以添加integer
1至增加一天。
您后来透露您使用的是timestamptz
,因此我们可以AT TIME ZONE
从表达式中删除。
在我的测试中,声明函数STABLE
产生了最佳性能,因为它允许函数内联。我本来希望IMMUTABLE
是最好的,但该声明对允许内联的内容更为挑剔。有关的:
在我的测试中快一点:
CREATE OR REPLACE FUNCTION f_tstz_interval_ceiling2(_tstz timestamptz, _int_seconds int)
RETURNS timestamptz AS
$func$
SELECT to_timestamp(trunc(extract(epoch FROM ($1 - interval '1 microsecond')))::int / $2 * $2 + $2)
$func$ LANGUAGE sql STABLE;
Run Code Online (Sandbox Code Playgroud)
更清洁的国际海事组织:
CREATE OR REPLACE FUNCTION f_tstz_interval_ceiling1(_tstz timestamptz, _int_seconds int)
RETURNS timestamptz AS
$func$
SELECT to_timestamp(ceil(extract(epoch FROM $1) / $2) * $2)
$func$ LANGUAGE sql STABLE;
Run Code Online (Sandbox Code Playgroud)
称呼:
SELECT f_tstz_interval_ceiling1(my_tstz, 600); -- 600 = seconds in 10 min
Run Code Online (Sandbox Code Playgroud)
为方便起见,您可以使用替代方法重载每个函数,将 ainterval
作为$2
:
CREATE OR REPLACE FUNCTION f_tstz_interval_ceiling1(_tstz timestamptz, _interval interval)
RETURNS timestamptz LANGUAGE sql STABLE AS
'SELECT f_tstz_interval_ceiling1($1, extract(epoch FROM $2)::int)';
Run Code Online (Sandbox Code Playgroud)
只需用提取的秒数调用第一个版本。然后你也可以调用:
SELECT f_tstz_interval_ceiling1(my_tstz, interval '10 min');
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3613 次 |
最近记录: |