Postgres: как вы округляете временную метку вверх или вниз до ближайшей минуты?

#postgresql

#postgresql

Вопрос:

Существует ли функция postgresql, которая вернет временную метку, округленную до ближайшей минуты? Входным значением является временная метка, а возвращаемое значение должно быть временной меткой.

Ответ №1:

Используйте встроенную функцию date_trunc(text, timestamp) , например:

 select date_trunc('minute', now())
  

Редактировать: Это сокращает до самой последней минуты. Чтобы получить округленный результат, сначала добавьте 30 секунд к временной метке, например:

 select date_trunc('minute', now()   interval '30 second')
  

Это возвращает ближайшую минуту.

Смотрите Функции и операторы даты / времени Postgres для получения дополнительной информации

Комментарии:

1. 1 за умный трюк с добавлением половины интервала и последующим усечением.

Ответ №2:

Ответ на аналогичный (и более общий) вопрос,

«… до ближайшего минутного интервала» (1 минута, 5 минут, 10 минут и т.д.)

 CREATE FUNCTION round_minutes(TIMESTAMP WITHOUT TIME ZONE, integer) 
RETURNS TIMESTAMP WITHOUT TIME ZONE AS $$ 
  SELECT 
     date_trunc('hour', $1) 
        cast(($2::varchar||' min') as interval) 
     * round( 
     (date_part('minute',$1)::float   date_part('second',$1)/ 60.)::float 
     / $2::float
      )
$$ LANGUAGE SQL IMMUTABLE;

CREATE FUNCTION round_minutes(TIMESTAMP WITHOUT TIME ZONE, integer,text) 
RETURNS text AS $$ 
  SELECT to_char(round_minutes($1,$2),$3)
$$ LANGUAGE SQL IMMUTABLE;

SELECT round_minutes('2010-09-17 16:23:12', 5);
-- 2010-09-17 16:25:00

SELECT round_minutes('2010-09-17 16:23:12', 10, 'HH24:MI');
-- 16:20
  

Адаптировано из http://wiki.postgresql.org/wiki/Round_time и до «точного раунда», как показал @CrowMagnumb.

Ответ №3:

Пытаясь использовать ответ Питера выше для создания функций потолка и пола, я обнаружил, что вы также должны учитывать секунды при вызове функции округления. Это мои наборы функций, которые будут округлять временные метки нижнего и верхнего пределов.

 CREATE OR REPLACE FUNCTION round_minutes( TIMESTAMP WITHOUT TIME ZONE, integer) 
RETURNS TIMESTAMP WITHOUT TIME ZONE AS $$ 
  SELECT date_trunc('hour', $1)   (cast(($2::varchar||' min') as interval) * round( (date_part('minute',$1)::float   date_part('second',$1)/ 60.)::float / cast($2 as float)))
$$ LANGUAGE SQL IMMUTABLE STRICT;

CREATE OR REPLACE FUNCTION floor_minutes( TIMESTAMP WITHOUT TIME ZONE, integer ) 
RETURNS TIMESTAMP WITHOUT TIME ZONE AS $$ 
    SELECT round_minutes( $1 - cast((($2/2)::varchar ||' min') as interval ), $2 );
$$ LANGUAGE SQL IMMUTABLE STRICT;

CREATE OR REPLACE FUNCTION ceiling_minutes( TIMESTAMP WITHOUT TIME ZONE, integer ) 
RETURNS TIMESTAMP WITHOUT TIME ZONE AS $$ 
    SELECT round_minutes( $1   cast((($2/2)::varchar ||' min') as interval ), $2 );
$$ LANGUAGE SQL IMMUTABLE STRICT;
  

Комментарии:

1. Благодаря исправлению (!) и расширению: теперь у нас есть полная библиотека «приблизительно минут». PS: Я думаю, вы можете добавить int DEFAULT 5 (второй параметр), чтобы упростить наиболее частое использование.

2. Ops, еще одна проблема: использование LANGUAGE SQL IMMUTABLE .

3. Это не совсем правильно: каждый нечетный 10-минутный интервал (10, 30, 50) будет соответствовать интервалу ниже него. например, select floor_minutes('2022-12-14 22:30:00', 10); возвращает, 2022-12-14 22:20:00 а select floor_minutes('2022-12-14 22:20:00', 10); возвращает 2022-12-14 22:20:00

Ответ №4:

чтобы округлить временную метку в меньшую сторону

 CREATE or replace FUNCTION date_round_down(base_date timestamptz, round_interval INTERVAL) 
RETURNS timestamptz AS $BODY$
            SELECT TO_TIMESTAMP(EXTRACT(epoch FROM date_trunc('hour', $1))::INTEGER   trunc((EXTRACT(epoch FROM $1)::INTEGER - EXTRACT(epoch FROM date_trunc('hour', $1))::INTEGER) / EXTRACT(epoch FROM $2)::INTEGER) * EXTRACT(epoch FROM $2)::INTEGER) 
$BODY$ LANGUAGE SQL STABLE;

SELECT date_round_down('2017-06-02 16:39:35', '15 minutes') -- 2017-06-02 16:30:35
  

Комментарии:

1. Однако это не округляет 35 секунд в меньшую сторону, что, я думаю, ожидаемо

2. я пытался использовать это для округления до каждых 2 часов. не работает.