here's an improved version of date_trunc
create cast (bigint as timestamptz) WITHOUT FUNCTION;
create cast (timestamptz as bigint) WITHOUT FUNCTION;
CREATE OR REPLACE FUNCTION date_trunc_by_interval( interval, timestamptz )
RETURNS timestamptz
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT
AS $$
select
case when $2::bigint >= 0::bigint then
$2::bigint - $2::bigint % (extract (epoch from $1)*1000000 ) ::bigint
else
$2::bigint - $2::bigint % (extract (epoch from $1)*1000000 ) ::bigint
- (extract (epoch from $1)*1000000 ) ::bigint
end ::timestamptz
$$;
this allows rounding to any fixed-length interval eg: '864 seconds' (divinding days into 100 parts) or '14 days' dividing the calendar into fortnights. the basis is '2000-01-01 00:00:00.0 +00' which is the epoch used to compute postgres
timestamp values.
it works by coercing the timestamptz value and the interval into bigints and doing integer arithmetic on them then coercing them back to timestamps
negative inputs need special handling (the case statement) as % causes rounding towards zero.