Reputation: 703
I have a table in Postgres with weekdays and a time (hours in 24h mode). Like:
weekday | time
---------------
sun | 04
wed | 23
Now I need those times 5 hours earlier. How do I get to:
weekday | time
---------------
sat | 23
wed | 18
Upvotes: 1
Views: 62
Reputation: 51609
another not less ugly way:
t=# with a as (
with
i as (select 5 h)
, a as (
select to_char(g, 'dy'),g delta
from generate_series('2017.05.15','2017.05.21','1 day'::interval) g
)
select s145.*,delta + (time||' hours')::interval - concat(h,' hours')::interval nt
from s145
join i on true
join a on a.to_char = weekday
)
select to_char(nt, 'dy'), to_char(nt,'HH24')
from a;
to_char | to_char
---------+---------
sat | 23
wed | 18
(2 rows)
and for eg 2 hours:
t=# with a as (
with
i as (select 2 h)
, a as (
select to_char(g, 'dy'),g delta
from generate_series('2017.05.15','2017.05.21','1 day'::interval) g
)
select s145.*,delta + (time||' hours')::interval - concat(h,' hours')::interval nt
from s145
join i on true
join a on a.to_char = weekday
)
select to_char(nt, 'dy'), to_char(nt,'HH24')
from a;
to_char | to_char
---------+---------
sun | 02
wed | 21
(2 rows)
I took '2017.05.15'
because I know it is last monday. It will respect time switch that probably not what the op wants. of course it is easily avoidabe with set timezone to 'utc'. But I don't want to complicate already ugly code even more
Upvotes: 2
Reputation: 50209
You can use a CASE statement to get the results you desire. It just gets a little ugly, but it's not unmanageable.
SELECT
CASE WHEN time - 5 < 0 THEN
CASE
WHEN weekday = 'Sun' THEN 'Sat'
WHEN weekday = 'Sat' THEN 'Fri'
WHEN weekday = 'Fri' THEN 'Thu'
WHEN weekday = 'Thu' THEN 'Wed'
WHEN weekday = 'Wed' THEN 'Tue'
WHEN weekday = 'Tue' THEN 'Mon'
WHEN weekday = 'Mon' THEN 'Sun'
END
ELSE weekday
END as weekday,
CASE WHEN time - 5 < 0 THEN 24 - (time-5) ELSE time-5 END as time
FROM yourtable;
You could use a CTE so that you only have to monkey with changing that "5" in one spot too. Also adding the ability to put a positive or negative number and handle rolling forward a day:
WITH timeshift AS
(
SELECT -5 as hours
)
SELECT
CASE
WHEN time + timeshift.hours < 0 THEN
CASE
WHEN weekday = 'Sun' THEN 'Sat'
WHEN weekday = 'Sat' THEN 'Fri'
WHEN weekday = 'Fri' THEN 'Thu'
WHEN weekday = 'Thu' THEN 'Wed'
WHEN weekday = 'Wed' THEN 'Tue'
WHEN weekday = 'Tue' THEN 'Mon'
WHEN weekday = 'Mon' THEN 'Sun'
END
WHEN time + timeshift.hours >= 24 THEN
CASE
WHEN weekday = 'Sat' THEN 'Sun'
WHEN weekday = 'Sun' THEN 'Mon'
WHEN weekday = 'Mon' THEN 'Tue'
WHEN weekday = 'Tue' THEN 'Wed'
WHEN weekday = 'Wed' THEN 'Thu'
WHEN weekday = 'Thu' THEN 'Fri'
WHEN weekday = 'Fri' THEN 'Sat'
END
ELSE weekday
END as weekday,
CASE
WHEN time + timeshift.hours < 0 THEN 24 - (time + timeshift.hours)
WHEN time + timeshift.hours >= 24 THEN (time + timeshift.hours) - 24
ELSE time + timeshift.hours
END as time
FROM yourtable, timeshift
Upvotes: 2