How to round to nearest X minutes with PL/pgSQL?

后端 未结 7 1473
伪装坚强ぢ
伪装坚强ぢ 2021-01-07 03:36

How I can round to nearest X minutes?

Here\'s my attempt:

DECLARE
  _stamp ALIAS FOR $1; -- timestamp
  _nearest ALIAS FOR $2; -- minutes (integer)
         


        
相关标签:
7条回答
  • 2021-01-07 03:46

    Further to my previous answer, here's a function that puts it all together and does exactly what you ask for:

    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;
    

    And here's an example of calling it:

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

    You can supply any interval you want and it should work. As coded it rounds to the nearest interval, either up or down.

    If you wanted to truncate instead then just remove the + EXTRACT(epoch FROM $2)::integer / 2).

    Hopefully this will now act as a definitive answer that accepts the correct argument types (interval rather than integer number of minutes).

    0 讨论(0)
  • 2021-01-07 03:49

    Instead of adding or subtracting

    _minutes * interval '1 minute'

    you should be subtracting

    (_minutes % _nearest) * interval '1 minute'

    or adding

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

    0 讨论(0)
  • 2021-01-07 03:52

    This could be also useful: A function to round a Timestamp up to 5 minutes. You can easily modify it to get it working with any field of the timestamp and any quantity of that field.

    round_time function

    0 讨论(0)
  • 2021-01-07 03:53

    This seems to work:

    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;
    

    Thanks to Stephen Denne :)

    0 讨论(0)
  • 2021-01-07 04:01

    The round time function looks good. Another way to do it which will work for any unit of time without modification would be the following:

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

    Where the two references to 300 are the number of seconds you wish to round to, e.g. 300 = 5 minutes. By using integer maths you are truncating and then multiplying out the number of seconds from the epoch to give the rounded value.

    By using a simple cast this will always round down, but you could change the rounding to round to nearest if you wanted.

    If you want to round to the nearest 15 minutes then use 900 instead of 300. Nearest hour and a half would be 5400. Etc.

    0 讨论(0)
  • 2021-01-07 04:07

    Use the function date_trunc('src', timestamp [value]).

    See the documentation: http://www.postgresql.org/docs/9.1/static/functions-datetime.html

    0 讨论(0)
提交回复
热议问题