为什么postgres显示相同间隔值的两种不同格式?

时间:2016-06-29 18:58:11

标签: sql postgresql pgadmin postgresql-9.5

我正在帮助这个 question 尝试更改间隔的格式。

from '01 day 22:10:37'  to  '46:10:37'

我给出了一个字符串操作的解决方案。但后来我发现postgres可以在两种不同的格式上显示相同的间隔。

SELECT '2016-01-27 08:51:02'::timestamp - '2016-01-25 10:40:25'::timestamp end_date,
       '46:10:37'::interval interval_date;
有趣的是。执行逆过程的 function

 justify_hours('46:10:37'::interval) --> '1 day 22:10:37'

所以我想知道是否有解决这个问题的直接方法。为什么相同的区间值有两个不同的结果。

pgAdmin输出:

enter image description here

2 个答案:

答案 0 :(得分:4)

当间隔两个时间戳之间的差异时,它总是合理为几小时(即它具有标准格式)。例子:

select
    '2015-01-01 13:0:0'::timestamp - '2014-01-01 23:0:0'::timestamp, --> 364 days 14:00:00
    '2015-01-01 13:0:0'::timestamp - '2014-01-01 03:0:0'::timestamp, --> 365 days 10:00:00
    '2015-01-01 13:0:0'::timestamp - '2015-01-01 03:0:0'::timestamp; --> 10:00:00

间隔计算分别在日期部分和时间部分执行,因此它们可能会导致奇怪的格式。例子:

select 
    '2 day 1:00:00'::interval- '1 day 2:00:00'::interval,    --> 1 day -01:00:00 (!!)
    '2 day 100:00:00'::interval+ '1 day 60:00:00'::interval, --> 3 days 160:00:00
    '2 day 100:00:00'::interval- '2 day 60:00:00'::interval; --> 40:00:00

对于这种情况,Postgres开发人员为格式标准化提供了适当的功能

select 
    justify_hours('1 day -01:00:00'),  --> 23:00:00
    justify_hours('3 days 160:00:00'), --> 9 days 16:00:00
    justify_hours('40:00:00');         --> 1 day 16:00:00

然而他们并不认为反向操作是必要的。在this answer中,我提出了一个将间隔的日期部分转换为小时的函数。我认为justify_hours()可以(通过一些小的改动)某种反向功能

create or replace function unjustify_hours(interval)
returns interval language sql as $$
    select format('%s:%s',
        (extract (epoch from $1) / 3600)::int,
        to_char($1, 'mi:ss'))::interval;
$$;

select 
    unjustify_hours('23:00:00'),        --> 23:00:00
    unjustify_hours('9 days 16:00:00'), --> 232:00:00
    unjustify_hours('1 day 16:00:00');  --> 40:00:00

函数to_char(interval, text)在这里没有用,如

select 
    to_char(interval '23:00:00', 'hh24:mi:ss'),        --> 23:00:00
    to_char(interval '9 days 16:00:00', 'hh24:mi:ss'), --> 16:00:00 (!)
    to_char(interval '1 day 16:00:00',  'hh24:mi:ss'); --> 16:00:00 (!)

请注意,可以通过多种方式正确格式化间隔:

select 
    justify_hours('100:00:00'),        --> 4 days 04:00:00
    justify_hours('1 days 76:00:00'),  --> 4 days 04:00:00
    justify_hours('2 days 52:00:00'),  --> 4 days 04:00:00
    justify_hours('5 days -20:00:00'); --> 4 days 04:00:00

the documentation

  

根据SQL标准,间隔值的所有字段都必须   具有相同的符号,因此一个主要的负号适用于所有字段;   例如,区间文字中的负号' -1 2:03:04'   适用于日期和小时/分钟/秒部分。 PostgreSQL的   允许田地有不同的标志,传统上对待   文本表示中的每个字段都是独立签名的,所以   小时/分钟/秒部分在此被认为是正面的   例。如果IntervalStyle设置为sql_standard,则为前导符号   被认为适用于所有领域(但仅限于没有其他标志   出现)。否则使用传统的PostgreSQL解释。   为避免含糊不清,建议附加明确的符号   每个字段,如果任何字段为负数。

  

内部间隔值存储为月,日和秒。   这样做是因为一个月中的天数变化,一天变化   如果夏令时调整,可以有23或25小时   参与其中。月份和日期字段是整数,而秒数   字段可以存储分数。因为间隔通常是从   常量字符串或时间戳减法,此存储方法有效   在大多数情况下。函数justify_days和justify_hours是   可用于调整超出正常范围的日期和时间   的范围内。

答案 1 :(得分:0)

来自https://www.postgresql.org/docs/9.5/static/functions-formatting.html

  

to_char(interval)格式为HHHH12,如12小时制,   即0小时和36小时输出为12,而HH24输出满   小时值,间隔时间可超过23小时。

来自https://www.postgresql.org/docs/8.2/static/functions-formatting.html

  

to_char(interval)HHHH12格式设置为一天中的小时数   HH24可以输出超过一天的小时数,例如> 24

我猜第一个使用基于减法结果的隐式格式,第二个使用基于输入的显式格式。