unlimit
unlimit

Reputation: 3752

postgresql `at time zone` incorrect behaviour?

I have a simple postgresql table with the following data:

create table ti (
  l text,
  t timestamp without time zone
  );

insert into ti(l, t) values ('now', now());

I do a select using at time zone, I expect UTC + 5.30 hours

select now(), t, t at time zone 'Asia/Kolkata' from ti;

But this is what I get:

now|    t|  timezone
2019-06-06T12:11:42.576388Z|    2019-06-06T11:50:48.178689Z|    2019-06-06T06:20:48.178689Z

It subtracted 5.30 hours instead of adding them.

Sqlfiddle here

Upvotes: 1

Views: 552

Answers (1)

Jeremy
Jeremy

Reputation: 6713

now() returns a timestamp with time zone. The time zone info will be stripped off when it is cast to a timestamp without time zone when it is saved in your table, but the actual value saved in there will depend on the session time zone.

You can see this behavior pretty easily:

postgres=# begin;
BEGIN
postgres=# set time zone utc;
SET
postgres=# insert into test select now();
INSERT 0 1
postgres=# set time zone 'US/Eastern';
SET
postgres=# insert into test select now();
INSERT 0 1
postgres=# select * from test;
             a
----------------------------
 2019-06-06 12:46:10.475424
 2019-06-06 08:46:10.475424
(2 rows)

A little more explanation after your comment. I think the issue you are having is with converting between timestamp and timestamptz. Timestamps are much less confusing if you stick with just timestamptz. Let's remove now() from the discussion, since that adds an additional layer of complexity because converting from the result of now() to a timestamp without time zone depends on the session time zone.

select '2019-06-06 12:00:00UTC'::timestamp with time zone, 
       ('2019-06-06 12:00:00UTC'::timestamp with time zone) at time zone 'Asia/Kolkata';
      timestamptz       |      timezone
------------------------+---------------------
 2019-06-06 12:00:00+00 | 2019-06-06 17:30:00

I believe this is what you expect? We convert from a timestamp with time zone to a timestamp without time zone at a specific time zone.

What you are doing is similar to this, though:

select '2019-06-06 12:00:00UTC'::timestamp with time zone, 
  (('2019-06-06 12:00:00UTC'::timestamp with time zone)::timestamp without time zone) at time zone 'Asia/Kolkata';
      timestamptz       |        timezone
------------------------+------------------------
 2019-06-06 12:00:00+00 | 2019-06-06 06:30:00+00
(1 row)

I think you will find this much less confusing if you can store timestamp with time zone instead of timestamp without time zone.

Upvotes: 2

Related Questions