4

I use timestamp(3) with time zone in my database for the tables when one is necessary, this is almost any case in my situation.

I need to select all columns of a table possibly in a much more complex query than the following.

My question is how to get the timestamps (with time zone) at the desired time zone with SQL at time zone '<TIMEZONE>' for a select expression like q.* one of which is the timestamp (with time zone) column. I might have subqueries with the same situation. Is there an expression to achieve this for query wide?

SELECT
    q.*, -- created_at timestamp (with time zone) is already in here
    q.created_at AT TIME ZONE 'EET', --instead of this redundant column selection
    u.name AS author,
    u.reputation,
    CASE WHEN count(t.*)=0 THEN '[]' ELSE json_agg(t.*) END as tags
FROM posts q

-- authors
JOIN users u
ON q.author_id = u.id

-- tags
left join post_has_tag p_h_t
on q.id = p_h_t.post_id
left join tags t
on p_h_t.tag_id = t.id

WHERE q.post_type = 'question'
group by q.id, u.id;
sçuçu
  • 2,960
  • 2
  • 33
  • 60

2 Answers2

1

If your columns are of type timestamp, then using AT TIME ZONE is the correct way to convert them to a specific time zone.

However, don't use EET. Use a specific locality-based time zone from this list, such as Europe/Bucharest - or whatever is applicable for you.

Alternatively, if your columns are of type timestamp with time zone, then you can set the session's time zone and postgres will do the conversion for you:

SET TIME ZONE 'Europe/Bucharest'

You should read up on the docs to understand the difference of these two timestamp types.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • By 'session' do you mean the current transaction, or the query, as it is a transaction implicitly, too? – sçuçu Aug 29 '16 at 19:28
  • See [these docs](https://www.postgresql.org/docs/current/static/sql-set.html). Basically, `SESSION` is the default, and is scoped for the entire connection to the db. `LOCAL` is for the current transaction. – Matt Johnson-Pint Aug 29 '16 at 20:18
  • Currently I use the `SET TIME ZONE` construct with my query in the question and similar ones. However, the timestamps inside the `post` table ,the first table -the leftest in joins is not considered in the set time zone. The ones in `tags` table were output in specified time one by the clause at the beginnig. What can be the reason for this? – sçuçu Aug 31 '16 at 09:35
  • `timestamp` and `timestamptz` are two different types. The session/local time zone setting only affects `timestamptz` (aka "timestamp with time zone") – Matt Johnson-Pint Aug 31 '16 at 17:41
  • all the fields related to times and dates are my `timestamp(3) with time zone` values, both in `posts` table and `tags` table. – sçuçu Aug 31 '16 at 19:44
  • Everything is ok in my *pgAdmin3 SQL Editor*. When I write the query in my question with `set local time zone 'Europe/Oslo'` I get bot the `posts` and `tags` table `created_at` fields correct with `+2` offset in the output. However, when I put it in a route function in my *Nodejs* *express.js* server with *pg-promise* as the connection lib, I only get the `tags` table `created_at` field correct with the time in Oslo with timezone appended as expected, I get `created_at` field of the `posts` table in UTC as not expected. Does not the set local directive bind all the query? – sçuçu Aug 31 '16 at 19:56
  • Sorry, you're asking things I'm not familiar with. Perhaps others can help. Maybe edit your question or ask a new one? – Matt Johnson-Pint Aug 31 '16 at 20:19
  • Sorry. Yiu are right, maybe I should ask it as a separate question. – sçuçu Aug 31 '16 at 21:55
0

There is no magic setting to convert all columns of data type timestamptz to timestamp. But you can set the desired target time zone (temporarily) to adjust the display (the text representation) of the timestamptz value:

BEGIN;
SET LOCAL timezone = 'EET';
SELECT q.*, -- including created_at timestamp as original timestamptz type
     , u.name AS author,
     , ...

 -- do something with your data

COMMIT;  -- or ROLLBACK; doesn't matter for just SELECT

This is not the same as applying the AT TIME ZONE construct, which actually converts timestamp to timestamptz and vice versa. Details:

Effects of SET LOCAL last till the end of the transaction.

And (like @Matt already mentioned) it's generally (even if a bit more expensive) preferable to use actual time zone names over time zone abbreviations. Time zone names take DST and other peculiarities of the time zone into account:

SET LOCAL timezone = 'Europe/Istanbul';

Demo

BEGIN;
SET timezone = 'Europe/Istanbul';
SELECT now();

now
-----------------------------
2016-08-29 22:39:09.275647+03

SET timezone = 'UTC';
SELECT now();

now
-----------------------------
2016-08-29 19:39:09.275647+00

COMMIT;
Community
  • 1
  • 1
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • I am little bit more confused now. I use `timestamp with time zone` in all my tables.I need to show different time zone users the correct representation of time according to their time zones.While writing I do not do any special things just insert or use `CREATE_TIMESTAMP`. My db can be in a different time zone than the GMT. However, while I read I have planned to read with `at time zone` clause, with the full time zone names I will do it, so that the users see the times in their time zones. But only problem I see is with the syntax of the `at time zone` it cannot apply to a filed inside `p.*` – sçuçu Aug 29 '16 at 19:25
  • I have come to those conclusions and application desicions regarding timestamp usage after reading the mentioned SO question and some other, in which you @Erwin was involved, many thanks . Am I missing something? – sçuçu Aug 29 '16 at 19:27
  • How does Postgres know about "their timezone"? If they query with the respective time zone set in the session, the display is adjusted *automatically*. – Erwin Brandstetter Aug 29 '16 at 19:47
  • I will get their timezone from the request, somehow. Any way I need to take it from the user to query Postgres correctly, whether with setting the session timezone, or with `at time zone`, I may be wrong with the idea of usage of this second SQL construct with `timestamp with timezone` – sçuçu Aug 29 '16 at 19:53
  • I get a `query result with 5 rows discarded. Query returned successfully with no result in 20 msec. ` message in the pgAdmin3 SQL Editor. When I omit the begin and commit it gives rows, 5 rows, from the table, also the time zone set above is applied What is the reason? – sçuçu Aug 30 '16 at 15:10
  • By the way, from node.js with `pg-promise` I can get the `p.created_at` from the `posts` table as `"created_at":"2016-08-30T15:14:03.869Z"` which is in `GMT`, but another `timestamptz` type column from the `tags` table created with the same post at the same time is`"created_at":"2016-08-30T17:14:03.869+02:00"` that is presented accordingly, according to the set time zone with `SET LOCAL TIME ZONE 'Europe/Oslo';`. Note they are in the same query, even same transaction, the second one is just in the join parts following. – sçuçu Aug 30 '16 at 15:23
  • What is the reason for that? A bug in `pg-promise`? – sçuçu Aug 30 '16 at 15:43
  • @Işık: `5 rows discarded`: Execute each command of the demo separately to see results, not the whole demo at once. `"2016-08-30T15:14:03.869Z"` is a `timestamp` literal (no offset), while `"2016-08-30T17:14:03.869+02:00"` is a timestamptz literal (with offset). Not sure what's going on there. – Erwin Brandstetter Aug 31 '16 at 23:56