3

如何四舍五入到最接近的 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
4

8 回答 8

2

而不是加法或减法

_minutes * interval '1 minute'

你应该减去

(_minutes % _nearest) * interval '1 minute'

或添加

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

于 2010-01-26T02:12:25.970 回答
2

回合时间功能看起来不错。另一种无需修改即可在任何时间单位内工作的方法如下:

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

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

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

如果您想四舍五入到最接近的 15 分钟,则使用 900 而不是 300。最近一个半小时将是 5400。等等。

于 2012-09-10T10:31:32.383 回答
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).

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

于 2012-09-10T10:44:42.497 回答
2

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
于 2021-04-01T15:25:15.443 回答
1

这也很有用:将时间戳四舍五入最多 5 分钟的函数。您可以轻松修改它以使其与时间戳的任何字段和该字段的任何数量一起使用。

round_time 函数

于 2012-02-22T13:16:03.240 回答
0

您可以将其作为一个简单的 SQL 语句执行,将 CURRENT_TIMESTAMP 替换为您的 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感谢StuckMojo

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

更新@stephen,确实如此——尽管从技术上讲这不是问题所要求的。

CREATE OR REPLACE FUNCTION round_trunc ( in text, in timestamp ) RETURNS timestamp without time zone  AS $$
  SELECT pg_catalog.date_trunc(
      $1
      , $2::timestamp without time zone
        + ('0.5 ' || $1 )::interval
  )
$$ LANGUAGE sql VOLATILE;

哦等等,我明白他在问什么,他想四舍五入到最近的抽象时间子单位。像一刻钟,我离这里很远。

于 2010-01-25T23:37:15.983 回答
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;

感谢斯蒂芬丹恩 :)

于 2010-01-26T08:32:11.747 回答
-1

使用功能date_trunc('src', timestamp [value])

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

于 2012-02-20T12:23:06.297 回答