在PostgreSQL

时间:2016-09-15 17:51:33

标签: postgresql datetime plpgsql

我想找出两个timestamp s(带有时区)的自定义interval数量的差异。所以函数应该像custom_diff(timestamptz from, timestamptz to, interval custom)

请注意,它不等同于(to-from)/customcustom_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

但我不确定它是否正确,仍在等待现有/普通解决方案的消化。

1 个答案:

答案 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时间。