简体   繁体   中英

custom DATE_TRUNC timeframes

I'm trying to customize the timeframe in my DATE_TRUNC function, so instead of the typical

DATE_TRUNC('hour', user.created_at)

ideally, I want something along the lines of

DATE_TRUNC('3 hours', user.created_at)

but of course that's not a valid time zone unit, so I get an error like

ERROR:  timestamp with time zone units "3 hour" not recognized
********** Error **********

ERROR: timestamp with time zone units "3 hour" not recognized
SQL state: 22023

I know I could modify a CASE statement like

'2019-7-26'::DATE + {{number}} * (CASE WHEN 'hour' THEN '1 hour'::INTERVAL
                                      WHEN 'minute' THEN '1 minute'::INTERVAL
                                      WHEN 'second' THEN '1 second'::INTERVAL
                                   END)

but I'm not looking to shift the timestamp and I'm not sure how to modify it to achieve what I want above.

You could do this: date_trunc('hour', user.created_at) + interval '3 hour'

What result are you trying to get? You said that you don't want to shift the timestamp, so what are you trying to have return with the '3 Hours'?

A little painful, but you can do:

select (date_trunc('day', user.created_at) + 
        floor(extract(hour from user.created_at) / 3) * interval '3 hour'
       )

I'm not sure I fully understand what your "DATE_TRUNC('3 hours', user.created_at)", but it looks like returning some interval from midnight. So I'll proceed with that assumption.
The built in date_trunc function is defined to take 2 parameters, text and timestamp (actually overloaded for timestamp with time zone and timestamp without time zone). You could extend this overload concept and with overloads taking an interval instead of text." So

   create or replace function date_trunc (intv interval, ts timestamp without time zone)
      returns timestamp without time zone 
     language sql  immutable leakproof
    as $$
        select date_trunc('day', ts) + intv;
    $$;

    create or replace function date_trunc (intv interval, ts timestamp with time zone)
      returns timestamp with time zone
     language sql  immutable leakproof
    as $$
        select date_trunc('day', ts) + intv;
    $$;

    -- Test
    select date_trunc('3 hours'::interval, now()) with_ts
         , date_trunc('3 hours'::interval, now()::timestamp without time zone) without_ts;

However I don't like redefining built in functions, causes whole lot of confusion when something goes wrong later. So instead of overloading the built-in I would create a new user defined function name; like Date_Trunc_To_Interval. But you're free to be dangerous.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM