postgresql how can i minus 5 minutes in date - postgresql

I want this time minus 5 minutes
I tried current_date but it gives me an other time than cet.
I need to get current date minus 5 minutes in postrgesql
SELECT now() AT TIME ZONE 'Europe/Brussels' AS europe ;

SELECT current_timestamp AT TIME ZONE 'Europe/Brussels' - INTERVAL '5 minutes';
Produces:
┌───────────────────────────┐
│ column │
├───────────────────────────┤
│ 2021-03-24 12:16:55.94187 │
└───────────────────────────┘
https://www.postgresql.org/docs/current/functions-datetime.html

Related

How can I generate a series of date ranges that fall between a start date and end date?

I would like to generate an array of all the time ranges that fall within 4 pm-9 pm between a start and end date
start_date | end_date
----------------------------------------
2020-11-01 16:30:00 | 2020-11-03 18:30:00
The query should be able to turn the above table into:
row | start_date | end_date
------------------------------------------------
1 | 2020-11-01 16:30:00 | 2020-11-01 21:00:00
------------------------------------------------
2 | 2020-11-02 16:00:00 | 2020-11-02 21:00:00
------------------------------------------------
3 | 2020-11-03 16:00:00 | 2020-11-03 18:30:00
Could someone point me in the right direction on how to approach this?
I would do it like this:
with input as (
select '2020-11-01 16:30:00'::timestamptz as start_date,
'2020-11-03 18:30:00'::timestamptz as end_date
)
select row_number() over (order by ddate) as row,
case
when start_date::date = ddate
and start_date > ddate + interval '16 hours'
then start_date
else ddate + interval '16 hours'
end as start_date,
case
when end_date::date = ddate
and end_date < ddate + interval '21 hours'
then end_date
else ddate + interval '21 hours'
end as end_date
from input
cross join lateral
generate_series(
case
when start_date::time > '21:00' then start_date::date + interval '1 day'
else start_date::date
end,
case
when end_date::time < '16:00' then end_date::date - interval '1 day'
else end_date::date
end,
interval '1 day') as gs(ddate)
;
┌─────┬────────────────────────┬────────────────────────┐
│ row │ start_date │ end_date │
├─────┼────────────────────────┼────────────────────────┤
│ 1 │ 2020-11-01 16:30:00-05 │ 2020-11-01 21:00:00-05 │
│ 2 │ 2020-11-02 16:00:00-05 │ 2020-11-02 21:00:00-05 │
│ 3 │ 2020-11-03 16:00:00-05 │ 2020-11-03 18:30:00-05 │
└─────┴────────────────────────┴────────────────────────┘
(3 rows)
When you use generate_series with hours instead of days as in the solution of #MikeOrganek, you can filter them directly. Start and end hours should be "complete hours", which can be achieved using date_trunc(). Because date_trunc cuts the final minutes of the end date, it makes sense, to create the series an hour more; this is why an hour is added in the example.
Finally GROUP BY date and give out the MIN and MAX time. With least() and greatest() you can adjust the edge cases.
step-by-step demo:db<>fiddle
SELECT
GREATEST(MIN(gs), start_date) as start_time,
LEAST(MAX(gs), end_date) as end_time
FROM
t,
generate_series(
date_trunc('hour', start_date),
date_trunc('hour', end_date) + interval '1 hour',
interval '1 hour'
) as gs
WHERE gs::time >= '16:00:00' and gs::time <= '21:00:00'
GROUP BY start_date, end_date, gs::date
ORDER BY gs::date
Another solution is to use generate_series() with a one day interval and construct the time part depending on the value of the time in start/end date for the first and last day.
with from_to (start_date, end_date) as (
values (timestamp '2020-11-01 16:30:00', timestamp '2020-11-03 18:30:00')
)
select g.nr as row,
g.d::date + case
when g.d::date = start_date::date and start_date::time > time '16:00' then start_date::time
else time '16:00'
end as start_date,
g.d::date + case
when g.d::date = end_date::date and end_date::time < time '21:00' then end_date::time
else time '21:00'
end as end_date
from from_to
cross join generate_series(start_date, end_date, interval '1 day') with ordinality as g(d,nr)
order by g.nr;
Online example

Calendar days since date in days

Given the following sqlfiddle: http://www.sqlfiddle.com/#!17/f483a/2/0
create table test (
start_date date
);
insert into test values ('2019/01/01');
select
start_date,
age(now()::date,start_date) as date_diff
from test;
Which generates the following output:
date_diff | 0 years 7 mons 27 days 0 hours 0 mins 0.00 secs
How could I instead generate the correct number of calendar days
239 days
without using a custom function?
Don't use the age function. Subtracting a date from a date yields an integer. now() returns a timestamp so you need to use current_date instead.
select start_date,
current_date - start_date as date_diff
from test;

Convert interval to number in postgresql

I have created a query which sums up the interval for respective date-time,
select sum(ts_polling) / count(ts_polling) as Average_Queue_Wait_Time , cast(time_start AS Date)
from callcent_queuecalls group by cast(time_start AS date) order by time_start DESC;
Is there a way to convert Average_Queue_Wait_Time from interval data type to number ?
You can get the number of seconds in an interval like this:
SELECT EXTRACT(epoch FROM INTERVAL '1 day 30 minutes 1.234 seconds');
┌───────────┐
│ date_part │
├───────────┤
│ 88201.234 │
└───────────┘
(1 row)

Postgresql combining date, time and microseconds into timestamp

I have a table with the following fields:
my_date my_time my_time2
2017-04-14 10:00:01 286115
How do I combine these fields into timestamp column like 2017-04-14 10:00:01.286115?
Unfortunately select my_date+my_time+my_time2 from my_table works fine only for the first two fields. Thanks in advance.
select date '2017-04-14' + time '10:00:01' + 286115 * interval '1usec';
┌────────────────────────────┐
│ ?column? │
╞════════════════════════════╡
│ 2017-04-14 10:00:01.286115 │
└────────────────────────────┘
(1 row)

Group by school year in postgres

I have a query where I count the number of rows for each year:
SELECT
count(*) as activation_count
, extract(year from activated_at) as year
FROM "activations"
WHERE ...
GROUP BY year
But I'd like instead to have years ranging from September to September instead of January to January. Thus grouping by school years instead of calendar years.
Can I modify my query to do that?
And more generally, is it possible to group by a time range and specify an offset to it, eg: extract(year from activated_at offset interval 2 month) as year (this is not working, just the idea of what I want)
What you essentially want is to treat all dates after September as "next year", so the following should work:
select count(*) as activation_count,
case
when extract(month from activated_at) >= 9 then extract(year from activated_at) + 1
else extract(year from activated_at)
end as school_year
from activations
group by school_year;
Assuming that someone whose activated_at is '2016-09-01' should be counted as year = 2017, you could add 4 months to activated_at when in the extract (translating (in the mathematical sense of the word) September to January).
SELECT * FROM activations ;
┌────────────────────────┐
│ activated_at │
├────────────────────────┤
│ 2016-08-01 00:00:00+02 │
│ 2016-09-01 00:00:00+02 │
│ 2016-10-01 00:00:00+02 │
│ 2017-02-02 00:00:00+01 │
└────────────────────────┘
(4 rows)
SELECT COUNT(*),
EXTRACT(year FROM (activated_at + '4 months'::interval)) AS year
FROM activations
GROUP BY year;
┌───────┬──────┐
│ count │ year │
├───────┼──────┤
│ 3 │ 2017 │
│ 1 │ 2016 │
└───────┴──────┘
(2 rows)
If it should be counted as year = 2016 you could remove 8 months instead.