显示Postgres功能的下一个半小时时间点

时间:2014-12-05 11:50:04

标签: sql postgresql postgresql-9.1

我正在尝试创建一个显示下半小时时间的函数。

所以当前时间是13:40时,我希望它显示14:00而不是13:30。

我所创造的,完成工作但是在最近的半小时时间,而不是未来最近的时间:

CREATE OR REPLACE FUNCTION round_timestamp(
         ts timestamptz
         ,round_secs int
        ) RETURNS timestamptz AS $$
        DECLARE
                _mystamp timestamp;
                _round_secs decimal;
        BEGIN
    _round_secs := round_secs::decimal;
    _mystamp := timestamptz 'epoch' 
            + ROUND((EXTRACT(EPOCH FROM ts))::int / _round_secs) * _round_secs
            * INTERVAL '1 second';
    RETURN _mystamp;
END; $$ LANGUAGE plpgsql IMMUTABLE;

有关如何使这项工作显示未来最近的半小时间隔的任何想法?

4 个答案:

答案 0 :(得分:1)

为了避免使用epoch和浮点算术,你可以依赖日期算术,还有一个好处是让它更清晰:

create or replace function round_tstz(ts timestamptz)
  returns timestamptz
as $$
  select date_trunc('hour', $1) +
         -- what hour will it be in 30 min?
         case date_trunc('hour', $1 + interval '30 min')
         -- the same: round to next half hour
         when date_trunc('hour', $1) then interval '30 min'
         -- not the same: round to next hour
         else interval '1 hour'
         end;
$$ language sql stable;

# select now()::timestamptz(0);
          now           
------------------------
 2014-12-05 14:34:30+01
(1 row)

# select round_tstz(now()), round_tstz(now() + interval '30 min');
       round_tstz       |       round_tstz       
------------------------+------------------------
 2014-12-05 15:00:00+01 | 2014-12-05 15:30:00+01
(1 row)

答案 1 :(得分:0)

您可以分别使用ceil() (or ceiling()) and floor()向上和向下舍入。

如果您的函数很简单,您也可以在LANGUAGE SQL中编写它,这使它更简单/可读(并且解析器也可以计划):

CREATE OR REPLACE FUNCTION round_timestamp(ts timestamptz, round_secs int)
  RETURNS timestamptz
  LANGUAGE SQL
  IMMUTABLE
AS $func$
SELECT timestamptz 'epoch'
  + ceiling(EXTRACT(EPOCH FROM ts) / round_secs)
  * round_secs
  * INTERVAL '1 second'
$func$;

SQLFiddle

答案 2 :(得分:0)

琐碎的是,在将其缩放回时间戳之前,在向下舍入的时期加1:

CREATE OR REPLACE FUNCTION round_timestamp(ts timestamptz, round_secs int)
    RETURNS timestamptz AS $$
BEGIN
    RETURN timestamptz 'epoch' 
            + (ROUND((EXTRACT(EPOCH FROM ts))::int / round_secs) + 1) * round_secs
            * INTERVAL '1 second';
END; $$ LANGUAGE plpgsql IMMUTABLE;

不需要局部变量。

答案 3 :(得分:0)

您需要将X分钟添加到时间戳中的当前分钟数M,其中:

X = 30 - M %30 - 30 *(( M %30)= 0):: int

您将除法的余数从30减去30,然后仅当该余数为0时,减去另外30,以便:保留00和:30值并且不会向上舍入。

例如,如果时间是14:11,那么M = 11,你需要增加19分钟到达14:30(30 - 11%30 = 19),14:47,M = 47,你需要增加13分钟才能达到15:00(30-47%30 = 13)。该规则的唯一例外是剩余部分为0的情况,即小时数,例如14:30,15:00等等 - 这就是公式中最后一个项发挥作用的地方 - 减去30 *的乘积( 0或1,取决于除法的剩余部分为30)。

CREATE FUNCTION round_up(timestamptz) RETURNS timestamptz AS $$
  SELECT
    $1 + '1 minute'::interval * (
      30 - (EXTRACT('minute' FROM $1)::int % 30)
         - 30 * ((EXTRACT('minute' FROM $1)::int % 30)=0)::int
    );
$$ LANGUAGE sql IMMUTABLE;