Convert day and hour in user time zone - ruby-on-rails-3

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;

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

How to get all data post midnight of different timezone?

I have a PostgreSQL table named testing with a column named creation_time as timestamp with time zone. The database timezone is UTC
Now I want to get all rows whose time is greater than 00:00 of the current day as per the timezone "America/New_York".
I know how to get all rows after local midnight:
SELECT * FROM testing
WHERE ( creation_time >= now()::date)
ORDER BY id DESC
But how to use this query with a different timezone?
Assuming "the current day" is also defined by NY time, not by the current timezone setting.
SELECT *
FROM testing
WHERE creation_time >= date_trunc('day', now() AT TIME ZONE 'America/New_York') AT TIME ZONE 'America/New_York'
ORDER BY id DESC;
Yes, AT TIME ZONE 'America/New_York' twice. No typo there.
now() AT TIME ZONE 'America/New_York') gets local NY time. date_trunc gets 00:00 of that day. The 2nd AT TIME ZONE 'America/New_York' converts the local time back to timestamptz, which we finally compare to.
If you want NY 00:00 of your local date, it's simpler:
WHERE creation_time >= CURRENT_DATE::timestamp AT TIME ZONE 'America/New_York'
Same time, but can be a different day!
CURRENT_DATE is the local date (date according to the time zone setting of the current session). Effectively the same as now()::date.
Further reading:
Ignoring time zones altogether in Rails and PostgreSQL

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

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'

Can't extract timezone_hour from postgres timestamp

ERROR: timestamp units "timezone" not supported
That's the error I get for all timezone fields.
Here's a minimal query you can run:
select extract(timezone_hour from now()::timestamptz at time zone 'US/Eastern');
What I want is the utc offset in hours. So this should return -4.
The requirement is that I use a dynamic time zone in the query. So I have a table of "facilities" with time zone strings, and I need to get the current time for each one.
So my end query should look something like this:
SELECT
EXTRACT(timezone_hour from now() with time zone timezone) # timezone is the name of the field
FROM facilities;
I thought I had it for a second with this, but this is giving me my current offset, not the offset of the tz I'm passing:
select
extract(timezone_hour from (select now()::timestamp at time zone 'US/Eastern'))
date_part
-----------
-7
I ended up getting this to work with creating two timestamps, one at utc and one at the desired time zone, but I'll leave this open just in case there's a better solution than my current one:
select
extract(hour from (
select (
select now() at time zone 'US/Eastern') - (select now() at time zone 'UTC')));
date_part
-----------
-4

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