我想找出两个timestamp
s(带有时区)的自定义interval
数量的差异。所以函数应该像custom_diff(timestamptz from, timestamptz to, interval custom)
。
请注意,它不等同于(to-from)/custom
(custom_diff('2016-08-01 00:00:00','2016-09-01 00:00:00','1 day')
正好是31,但('2016-08-01 00:00:00','2016-09-01 00:00:00')/'1 day')
= '1 month'/'1 day'
且不明确。
我也理解,一般来说,这种操作没有确切的结果(custom_diff('2016-08-01 00:00:00','2016-09-01 00:00:00','1 month 1 day'
)所以可以有一组功能(圆到最近,从圆到小,圆到 - upper和truncating,所有这些都应该返回整数。)
在PostgreSQL(PL / pgSQL)中有这种计算的标准/常用方法吗?我最感兴趣的是圆形到最近的功能。
我发明的最好方法是迭代地将interval custom
添加/减去timestamptz from
,然后与timestamptz to
进行比较。此外,它可以通过最初找到近似结果进行优化(例如,除以[{1}} s之间的秒数差异[近似timestamp
秒]),以减少迭代次数。
UPD 1:
为什么
interval custom
是一个错误的解决方案:让我们自己试试:
SELECT EXTRACT(EPOCH FROM (timestamp '2016-08-01 10:00'
- timestamp '2016-08-01 00:00'))
/ EXTRACT(EPOCH FROM interval '1 day');
结果是SELECT EXTRACT(EPOCH FROM ( TIMESTAMPTZ '2016-01-01 utc' -
TIMESTAMPTZ '1986-01-01 utc' ))
/ EXTRACT(EPOCH FROM INTERVAL '1 month');
。然后检查结果:
365.23...
结果是SELECT ( TIMESTAMPTZ '1986-01-01 utc' + 365 * INTERVAL '1 month' )
AT TIME ZONE 'utc';
。原因2016-06-01 00:00:00.000000
是错误的结果,因为此示例中的时间戳恰好描述了30年,并且在任何一年中总是恰好12个月,因此正确答案为365
。
UPD 2:
我的解决方案是
12*30=360
但我不确定它是否正确,仍在等待现有/普通解决方案的消化。
答案 0 :(得分:0)
您可以在extracting the epoch from both intervals之后获得准确的结果:
SELECT EXTRACT(EPOCH FROM (timestamp '2016-08-01 10:00'
- timestamp '2016-08-01 00:00'))
/ EXTRACT(EPOCH FROM interval '1 day'); -- any given interval
如果您想要舍入(截断)结果,一个简单的选项是将两者都强制转换为integer
。整数除法切断了其余部分。
SELECT EXTRACT(EPOCH FROM (ts_to - ts_from))::int
/ EXTRACT(EPOCH FROM interval '1 day')::int; -- any given interval
您可以轻松地将逻辑包装到IMMUTABLE
SQL函数中。
您从手册中的内容中得出了错误的结论。 timestamp
减法的结果是精确间隔,仅存储天数和秒数(不是月数)。所以结果是准确的。试试我的问题,它不是模棱两可的"。
您可以避免涉及数据类型interval
:
SELECT EXTRACT(EPOCH FROM ts_to) - EXTRACT(EPOCH FROM ts_from))
/ 86400 -- = 24*60*60 -- any given interval as number of seconds
但结果是一样的。
除了:
"精确"在处理时间戳时,这是一个难以捉摸的术语。您可能必须考虑DST规则和时区的其他极端情况。您可以在进行数学运算之前转换为UTC时间。