Frage

Wie kann ich mich auf die nächste X Minuten abrunden können?

Hier ist mein Versuch:

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;

Beispiel:

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

Wenn Rückkehr

2010-01-01 12:30:00
War es hilfreich?

Lösung

Statt Addieren oder Subtrahieren

_minutes * interval '1 minute'

Sie sollten

werden Subtrahieren

(_minutes % _nearest) * interval '1 minute'

oder das Hinzufügen

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

Andere Tipps

Die runde Zeitfunktion sieht gut aus. Eine andere Möglichkeit, es zu tun, die für jede Zeiteinheit ohne Änderungen funktionieren würde wie folgt vor:

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

Wenn die zwei Verweise auf 300 sind die Anzahl der Sekunden Sie runden möchten, z.B. 300 = 5 Minuten. Durch die Verwendung von Integer-Mathematik Sie Kürzen und dann die Anzahl der Sekunden aus der Epoche Ausmultiplizieren dem gerundeten Wert zu geben.

Durch eine einfache Verwendung werfen dies immer abrunden, aber man konnte die Rundung auf rund zum nächsten ändern, wenn Sie wollen.

Wenn Sie auf die nächsten 15 Minuten Runde wollen, dann 900 anstelle von 300 Nächste Stunde und eine Hälfte würde 5400. usw. sein.

Im Anschluss an meine vorherige Antwort, hier ist eine Funktion, die setzt sie alle zusammen und tut genau das, was man sich wünschen:

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;

Und hier ist ein Beispiel es der Aufruf:

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

Sie können ein beliebiges Intervall liefern Sie wollen, und es sollte funktionieren. Als codierte rundet es zum nächsten Intervall, entweder nach oben oder nach unten.

Wenn Sie stattdessen dann einfach entfernen Sie die + EXTRACT(epoch FROM $2)::integer / 2) abschneiden wollte.

Hoffentlich wird dies nun als endgültige Antwort handeln, dass die richtigen Argumenttypen akzeptiert (Intervall anstatt ganze Anzahl von Minuten).

Dies könnte auch nützlich sein: Eine Funktion bis 5 Minuten einen Zeitstempel bis runden. Sie können es leicht ändern, um es mit jedem Feld des Zeitstempels und jede Menge dieses Feldes zu erhalten zu arbeiten.

round_time Funktion

Sie können es als eine einfache SQL-Anweisung tun, Ersatz CURRENT_TIMESTAMP mit TIMESTAMP-Wert.

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 ;

Eine Optimierung wäre Zugabe von 30 Sekunden und dann nur date_trunc() tun, wusste ich dies vor, aber besonderer Dank irc://irc.freenode.net/#postgresql des StuckMojo

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

Update @stephen, sicher tut es -. Selbst spricht zwar technisch das ist nicht das, was die Frage genannt für

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;

Oh, Moment mal, ich sehe, was er fragt, er will rund zur nächsten abstrakten Teilzeiteinheit. Wie eine Viertelstunde, ich bin weg hier.

Das scheint zu funktionieren:

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;

Dank Stephen Denne:)

Mit der Funktion date_trunc('src', timestamp [value]).

Sehen Sie die Dokumentation: http://www.postgresql.org/ docs / 9.1 / static / Funktionen-datetime.html

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top