如何使用PL / pgSQL舍入到最近的X分钟?

时间:2010-01-25 23:11:51

标签: datetime postgresql function plpgsql

如何绕到最接近的X分钟?

这是我的尝试:

DECLARE
  _stamp ALIAS FOR $1; -- timestamp
  _nearest ALIAS FOR $2; -- minutes (integer)
  _minutes decimal;
  _ret timestamp;
BEGIN
  _ret := date_trunc('minute', _stamp);

  SELECT EXTRACT (minute FROM _ret)::integer INTO _minutes;

 IF (_minutes % _nearest < (_nearest / 2)) THEN
    RETURN _ret + _minutes * interval '1 minute';
  ELSE
    RETURN _ret - _minutes * interval '1 minute';
  END IF;

  RETURN _ret;
END;

示例:

SELECT round_to_nearest_minute ('2010-01-01 12:34:56', 15);

应该返回

2010-01-01 12:30:00

8 个答案:

答案 0 :(得分:2)

而不是添加或减去

_minutes * interval '1 minute'

你应该减去

(_minutes % _nearest) * interval '1 minute'

或添加

(_nearest - (_minutes % _nearest)) * interval '1 minute'

答案 1 :(得分:2)

圆形时间功能看起来不错。另一种可以在没有修改的情况下适用于任何时间单位的方法如下:

SELECT '1970-01-01'::timestamptz + EXTRACT(epoch FROM now())::integer / 300
            * 300 * interval '1 second';

对300的两个引用是您希望舍入的秒数,例如300 = 5分钟。通过使用整数数学,您将截断,然后乘以该纪元的秒数​​以给出舍入值。

通过使用简单的强制转换,这将始终向下舍入,但如果需要,您可以将舍入更改为舍入到最近。

如果你想要四舍五入到最接近的15分钟,那就用900而不是300.最近一个半小时是5400.等等。

答案 2 :(得分:2)

继我之前的回答之后,这里有一个将所有内容放在一起并完全符合您要求的功能:

CREATE FUNCTION date_round(base_date timestamptz, round_interval interval)
    RETURNS timestamptz AS $BODY$
SELECT '1970-01-01'::timestamptz 
    + (EXTRACT(epoch FROM $1)::integer + EXTRACT(epoch FROM $2)::integer / 2)
    / EXTRACT(epoch FROM $2)::integer
    * EXTRACT(epoch FROM $2)::integer * interval '1 second';
$BODY$ LANGUAGE SQL STABLE;

这是一个调用它的例子:

SELECT date_round(now(), '15 minutes');

你可以提供你想要的任何间隔,它应该工作。按照编码,它会向上或向下舍入到最近的间隔。

如果您想截断,请删除+ EXTRACT(epoch FROM $2)::integer / 2)

希望现在这将成为一个明确的答案,接受正确的参数类型(间隔而不是整数分钟)。

答案 3 :(得分:1)

这可能也很有用:将时间戳舍入为5分钟的函数。您可以轻松修改它以使其适用于时间戳的任何字段和该字段的任何数量。

round_time function

答案 4 :(得分:1)

PostgreSQL 14 将引入 date_bin 函数:

<块引用>

date_bin

date_bin ( interval, timestamp, timestamp ) → timestamp

函数 date_bin 将输入时间戳“装箱”到与指定原点对齐的指定间隔(步幅)中。

在完整单位(1 分钟、1 小时等)的情况下,它给出与类似的 date_trunc 调用相同的结果,但不同的是 date_bin 可以截断为任意间隔。

在这种情况下:

SELECT date_bin('15 minutes', TIMESTAMP '2010-01-01 12:34:56', TIMESTAMP '2010-01-01');
-- 2010-01-01 12:30:00

答案 5 :(得分:0)

您可以将它作为一个简单的SQL语句来替换,用您的TIMESTAMP值替换CURRENT_TIMESTAMP。

SELECT date_trunc('minute', CURRENT_TIMESTAMP::timestamp without time zone)
    + (
    CASE WHEN extract(second from CURRENT_TIMESTAMP ) >= 30
        THEN 1::text
        ELSE 0::text
    END
    || ' minute'

    )::interval ;

优化,会增加30秒,然后只是date_trunc(),我之前就知道了,但特别感谢irc://irc.freenode.net/#postgresql的{​​{1}}

StuckMojo

更新 @stephen,确定它确实 - 尽管从技术上说这不是问题所要求的。

<击>
SELECT date_trunc(
    'minute'
    , CURRENT_TIMESTAMP::timestamp without time zone
      + '30 seconds'::interval
);

<击>

等等,我看到他要求的是什么,他想要到最近的抽象子单位。就像四分之一小时一样,我离开这里了。

答案 6 :(得分:0)

这似乎有效:

DECLARE
  _stamp ALIAS FOR $1;
  _nearest ALIAS FOR $2;
  _seconds integer;
  _ret timestamp;
  _minutes decimal;
  _mod decimal;
BEGIN
  _ret := date_trunc('minute', _stamp);

  SELECT EXTRACT (minute FROM _ret)::integer INTO _minutes;

  _mod := _minutes % _nearest;

  IF (_mod > (_nearest / 2)) THEN
    RETURN _ret + (_nearest - _mod) * interval '1 minute';
  ELSE
    RETURN _ret - (_mod) * interval '1 minute';
  END IF;

  RETURN _ret;

END;

感谢Stephen Denne:)

答案 7 :(得分:-1)

使用函数date_trunc('src', timestamp [value])

请参阅文档:http://www.postgresql.org/docs/9.1/static/functions-datetime.html