Reputation: 843
Article model with default created_at
column
Rails config.time_zone = 'Warsaw'
I've got an article with created_at = local time 2012-08-19 00:15 (2012-08-18 22:15 in UTC).
To receive all articles created in 2012-08-19 (in local time).
Article.where(
"date_trunc('day', created_at AT TIME ZONE '#{Time.zone.formatted_offset}')
= '#{Date.civil(2012, 8, 19)}'"
)
Which generates SQL:
SELECT "articles".* FROM "articles"
WHERE (date_trunc('day', created_at AT TIME ZONE '+01:00') = '2012-08-19')
And returns an empty set. But if I run the same query in psql it returns an article ... which confuses me.
What am I doing wrong and how to fix it?
Upvotes: 1
Views: 1937
Reputation: 659207
Goal: To receive all articles created in 2012-08-19 (in local time).
'+01:00'
(like you use it) is a fixed time offset and cannot take DST (Daylight Saving Time) into account. Use a time zone name for that (not an abbreviation). These are available in PostgreSQL:
SELECT * FROM pg_timezone_names;
For Warsaw this should be 'Europe/Warsaw'
. The system knows the bounds for DST from its stored information and applies the according time offset.
Also, your query can be simplified.
As created_at
is a timestamp [without time zone]
, the values saved reflect the local time of the server when the row was created (saved internally as UTC timestamp).
There are basically only two possibilities, depending on the time zone(s) of your client.
Your reading client runs with the same setting for timezone
as the writing client: Just cast to date.
SELECT *
FROM articles
WHERE created_at::date = '2012-08-19';
Your reading client runs with a different setting for timezone
than the writing client: Add AT TIME ZONE '<tz name of *writing* client here>
'. For instance, if that was Europe/Warsaw
, it would look like:
...
WHERE (created_at AT TIME ZONE 'Europe/Warsaw')::date = '2012-08-19';
The double application of AT TIME ZONE
like you have it in your posted answer should not be necessary.
Note the time zone name instead of the abbreviation. See:
If you span multiple time zones with your application ..
.. set the column default of created_at
to now() AT TIME ZONE 'UTC'
- or some other time zone, the point being: use the same everywhere.
.. or, preferably, switch to timestamptz
(timestamp with time zone
).
Upvotes: 6
Reputation: 843
Linked answer helped. I have to run following query:
SELECT *
FROM articles
WHERE (created_at AT TIME ZONE 'UTC' AT TIME ZONE 'CEST')::date = '2012-08-19';
This question would need the exact definition of the column created_at (what data type exactly?)
Rails always creates created_at column as timestamp without time zone. So I have to make the first AT TIME ZONE 'UTC'
to say dbms that this timestamp is at UTC, and the second one to display date at CEST zone.
Upvotes: 1