What is the correct syntax for getting timestamps before a certain time? - sql

I would like to return all the timestamps from a database as long as they are before 6 am on the day they were made. I tried to do this:
SELECT source_created_at AT TIME ZONE 'US/PACIFIC' FROM time_entry
WHERE source_created_at AT TIME ZONE 'US/PACIFIC' < '06:00:00'::time
but got this error:
ERROR: operator does not exist: timestamp without time zone < time without time zone
LINE 2: WHERE source_created_at AT TIME ZONE 'US/PACIFIC' < '06:00:0...
I also tried < '06:00:00' and TIME'06:00:00; but got the same error. I'm new to SQL and the documentation has not been helpful here.

You cannot compare a timestamp to a time. You need to cast the timestamp to time first:
WHERE (source_created_at AT TIME ZONE 'US/PACIFIC')::time < '06:00:00'::time
Edit from the comments
If you want all timestamps before tomorrow 6 AM in the same timezone:
WHERE source_created_at at time zone 'US/PACIFIC'
< current_date at time zone 'US/PACIFIC' + interval '1 day 6 hour'

Related

Select data between dates and between times of day

I want to query rows for a given time range and also filter between given times of day.
Example I want to filter for times of day between '9.00 AM' and '10.00 PM' of every date within a given time range.
My table looks like this.
This is my sample code:
SELECT *
FROM public.energy
WHERE time >= date_trunc('month', NOW() - INTERVAL '1 MONTH') AT TIME ZONE 'Asia/Bangkok'
AND time < date_trunc('MINUTE', NOW()- INTERVAL '1 MONTH') AT TIME ZONE 'Asia/Bangkok'
AND name = 'SWU0001'
ORDER BY id DESC;
I already select data between dates that I want, but I want to filter for specific times.
SELECT *
FROM public.energy
WHERE name = 'SWU0001'
AND time >= date_trunc('month' , now() AT TIME ZONE 'Asia/Bangkok' - interval '1 month') AT TIME ZONE 'Asia/Bangkok' -- !
AND time < date_trunc('minute', now() AT TIME ZONE 'Asia/Bangkok' - interval '1 month') AT TIME ZONE 'Asia/Bangkok' -- !
AND (time AT TIME ZONE 'Asia/Bangkok')::time BETWEEN '09:00' AND '22:00' -- !!!
ORDER BY id DESC;
Don't call a timestamptz column "time". The name is misleading, and it's a basic type name.
Also, to work with local time of 'Asia/Bangkok' you need to get the local time for that time zone before applying date_trunc(), and cast the adjusted value back to timestamptz at the end. Basics:
Ignoring time zones altogether in Rails and PostgreSQL

Getting records relative to current date in timezone GMT+8

I wanted to create a report that generate yesterdays records relative to current date in Manila time. Result of the query is wrong until 8AM in Manila time.
I tried subtracting 1 day in current date and convert it in Asia/Manila timezone.
SELECT *
FROM table
WHERE date_field >= current_date at time zone 'Asia/Manila' - interval '1 day'
AND date_field < current_date at time zone 'Asia/Manila'
If today's current date time in manila is 2019-05-25 1AM
My expected result is records from '2019-05-24 00:00:00' - '2019-05-24 23:59:59'
But what I've got is records from '2019-05-23 00:00:00' - '2019-05-23 23:59:59'
Tried running it again at 8AM same date and the result is correct.
This is a little complicated. The current_date is defined at the UTC date. So, when you are calling it, the UTC date is "yesterday", and you are off by one day.
One way to fix this moves the current time into the time zone and then converts to a date:
WHERE date_field >= (current_timestamp at time zone 'Asia/Manila' - interval '1 day')::date AND
date_field < (current_timestamp at time zone 'Asia/Manila')::date

Match time with timezone between current time

I have stored time in DB as time without time zone and I want cast this time to time with timezone and then compare it with current time.
WHERE (my_time::time AT TIME ZONE country_timezone)
BETWEEN (current_time::time) - 60 * INTERVAL '1 minute'
AND (current_time::time) + 60 * INTERVAL '1 minute'
But the problem is that It is always compared against the time without time zone even after I casted It to time with timezone.
So for example
'my_time' => string '18:00:00+09' (length=11)
'current_time_plus' => string '10:51:47.997405'
'current_time_minus' => string '09:51:47.997405'
This should not match, but since my_time = 10:00:00 wihtout time zone then It is matching. How can I match the time as time with timezone ?
I would suggest not mixing times with time zone and without. I can't check myself but I assume
WHERE (my_time::time AT TIME ZONE country_timezone)
BETWEEN (current_time::timetz) - 60 * INTERVAL '1 minute'
AND (current_time::timetz) + 60 * INTERVAL '1 minute'
should work. because after you ::time AT TIME ZONE it becomes timetz and you compare it againt timestamptz::time, which gives you unexpected result

How to compare dates one with time zone and one without time zone

I have to compare the two dates to get the last 10 min records from database,I'm using postgresql,
I have write this query
select *
FROM x_table
WHERE x_time >= (NOW()::TIMESTAMP WITHOUT TIME ZONE - interval '10 minutes');
x_time is timestamp without time zone so that's why i'm converting the other to the same but it won't giving the result.
Query should written the last 1 min records but i think due to time zone issue it is not giving the result.
how can i resolve the issue?
If x_time is timestamp without time zone, you should specify proper time zone for NOW() function.
Try
select *FROM x_table WHERE x_time >= (NOW() at time zone '-04' - interval '10 minutes')

Convert day and hour in user time zone

I want to convert the group date (day + hour) to user time zone to show the list, i don't want update the db. I have several groups and this code is veeeeery slow.
# GROUP.RB
# day -> Date
# hour -> Time
# wday -> Integer
.
.
groups.each do |g|
new_day = g.in_gmt_day(user_time_zone) # <-- Concat group.day with group.hour and convert the result day with the user time zone.
g.wday = new_day.wday
g.hour = new_day
end
.
.
Any one can help me?
Thanks.
Let Postgres do this for you:
SELECT (day + hour) AT TIME ZONE '<source tz>' AT TIME ZONE 'localtime'
FROM groups;
This does
create a timestamp [without time zone] out of the two columns of data types date and time (assuming here, the question is vague about the exact data types):
day + hour
Set this timestamp at the time zone of the source, let's use 'Europe/London' as example. Results in a timestamp with time zone (or timestamptz for short):
(day + hour) AT TIME ZONE 'Europe/London'
Show the equivalent local timestamp [without time zone]:
(day + hour) AT TIME ZONE 'Europe/London' AT TIME ZONE 'localtime'
From here you can do anything with the value, like split up in day and time again, or format it any way you like with to_char():
WITH x AS (
SELECT (day + hour) AT TIME ZONE 'Europe/London' AT TIME ZONE 'localtime' AS ts
FROM groups
)
SELECT ts::date AS day, ts::time AS hour, to_char(ts, 'HH24') AS h24
FROM x;