Thread: Implicit conversion/comparision of timestamp with and without timezone

Implicit conversion/comparision of timestamp with and without timezone

From
Gerhard Wiesinger
Date:
Hello,

It is unclear to me how implicit conversion/comparision of timestamp with
and without timezone works.

--------------------------------------------------
-- datetime TIMESTAMP WITH TIME ZONE
-- datetime entries are with UTC+01 and UTC+02 done
-- 2009-03-09: UTC+01
-- 2009-06-12: UTC+02
-- current timezone: UTC+02

SELECT
   *
FROM
   table
WHERE
-- currently in UTC+02 timezone, entries in UTC+01 timezone
-- => works well with UTC+01 entry timezone, but why?
       datetime >= '2009-03-09 00:00:00.0'
   AND datetime  < '2009-03-10 00:00:00.0'
;

-- currently in UTC+02 timezone, entries in UTC+02 timezone
-- => works well with UTC+02 entry timezone, but why?
       datetime >= '2009-06-12 00:00:00.0'
   AND datetime  < '2009-06-13 00:00:00.0'
;

-- Same result, unclear why
       datetime >= TIMESTAMP WITHOUT TIME ZONE '2009-03-09 00:00:00.0'
   AND datetime  < TIMESTAMP WITHOUT TIME ZONE '2009-03-10 00:00:00.0'

-- Same result, unclear why
       datetime >= TIMESTAMP WITH TIME ZONE '2009-03-09 00:00:00.0'
   AND datetime  < TIMESTAMP WITH TIME ZONE '2009-03-10 00:00:00.0'

-- Same result2, unclear why
       datetime >= TIMESTAMP WITHOUT TIME ZONE '2009-06-12 00:00:00.0'
   AND datetime  < TIMESTAMP WITHOUT TIME ZONE '2009-06-13 00:00:00.0'

-- Same result2, unclear why
       datetime >= TIMESTAMP WITH TIME ZONE '2009-06-12 00:00:00.0'
   AND datetime  < TIMESTAMP WITH TIME ZONE '2009-06-13 00:00:00.0'

How is implicit conversion done? With timezone of datetime or timezone of
now() or timezone?

Would it make a difference when datetime would be declared with TIMESTAMP
WITHOUT TIME ZONE?
--------------------------------------------------

Thnx.

Ciao,
Gerhard

--
http://www.wiesinger.com/


Re: Implicit conversion/comparision of timestamp with and without timezone

From
Richard Huxton
Date:
Gerhard Wiesinger wrote:
> Hello,
>
> It is unclear to me how implicit conversion/comparision of timestamp
> with and without timezone works.

It's not entirely clear where the problem is. You don't say the results
you're getting or what you thought they should be.

> --------------------------------------------------
> -- datetime TIMESTAMP WITH TIME ZONE
> -- datetime entries are with UTC+01 and UTC+02 done
> -- 2009-03-09: UTC+01
> -- 2009-06-12: UTC+02
> -- current timezone: UTC+02

OK, so I've got this:
=> show timezone;
  TimeZone
----------
  UTC+02

SELECT * FROM tstest;
            d
------------------------
  2009-03-08 23:00:00-02
  2009-06-12 00:00:00-02
(2 rows)

So - it's showing the timestamp with timezones you mentioned but in the
current timezone. The UTC+02 actually being a -02 offset is just part of
the standards afaik. Note that midnight 2009-03-09 is 2009-03-08 in the
current timezone.

So - if we run EXPLAIN on your queries that should show us how the
values are getting typecast.

=> EXPLAIN SELECT * FROM tstest WHERE d >= '2009-03-09 00:00:00.0' AND d
< '2009-03-10 00:00:00.0';
                                                              QUERY PLAN


------------------------------------------------------------------------------------------------------------------------------------
  Seq Scan on tstest  (cost=0.00..42.10 rows=11 width=8)
    Filter: ((d >= '2009-03-09 00:00:00-02'::timestamp with time zone)
AND (d < '2009-03-10 00:00:00-02'::timestamp with time zone))


This comes back with zero rows because without an explicit timezone it
assumes our current one.


=> EXPLAIN SELECT * FROM tstest WHERE d >= '2009-06-12 00:00:00.0' AND d
< '2009-06-13 00:00:00.0';
                                                              QUERY PLAN


------------------------------------------------------------------------------------------------------------------------------------
  Seq Scan on tstest  (cost=0.00..42.10 rows=11 width=8)
    Filter: ((d >= '2009-06-12 00:00:00-02'::timestamp with time zone)
AND (d < '2009-06-13 00:00:00-02'::timestamp with time zone))

This will match one row.

Repeating the EXPLAIN on your other queries should show you what's
happening. If I've missed the point of your question, can you say what
results you get and what you think they should be.

--
   Richard Huxton
   Archonet Ltd

Re: Implicit conversion/comparision of timestamp with and without timezone

From
Gerhard Wiesinger
Date:
On Sun, 21 Jun 2009, Richard Huxton wrote:

> Gerhard Wiesinger wrote:
>> Hello,
>>
>> It is unclear to me how implicit conversion/comparision of timestamp with
>> and without timezone works.
>
> It's not entirely clear where the problem is. You don't say the results
> you're getting or what you thought they should be.
>

Ok, the "problem" is:
--------------------------------------------------
       datetime >= '2009-03-09 00:00:00.0'
   AND datetime  < '2009-03-10 00:00:00.0'
-- Index Cond: ((datetime >= '2009-03-09 00:00:00+01'::timestamp with time zone) AND (datetime < '2009-03-10
00:00:00+01'::timestampwith time zone)) 
--------------------------------------------------
       datetime >= '2009-04-01 00:00:00.0'
   AND datetime  < '2009-04-02 00:00:00.0'
-- Index Cond: ((datetime >= '2009-04-01 00:00:00+02'::timestamp with time zone) AND (datetime < '2009-04-02
00:00:00+02'::timestampwith time zone)) 

I would have expected that the 1st conversion is done with my current
timezone of the query time (CEST=+02). I don't see any problem with this
since all ugly timezone calculation are already done by PostgreSQL, but it
is nowhere (?) documented and was quite confusing me.

So for me documentation looks like:
A timestamp without any timezone information is converted into a
timestamp with time zone information (explicitly or implicitly) with the
with the time zone from the timestamp which has to be converted (and not
from the time zone from now()). The date and time information is not touched.

And:
A timestamp with timezone information is converted into a timestamp
without timezone information by removing just the timezone information. So
the date and time information is not touched.

Correct?

BTW:
I'm in CET (now CEST) timezone which is changed on last sunday in march
2:00 CET (and last sunday in October 3:00 CEST).

show timezone;
    TimeZone
---------------
  Europe/Vienna

>> --------------------------------------------------
>> -- datetime TIMESTAMP WITH TIME ZONE
>> -- datetime entries are with UTC+01 and UTC+02 done
>> -- 2009-03-09: UTC+01
>> -- 2009-06-12: UTC+02
>> -- current timezone: UTC+02
>
> OK, so I've got this:
> => show timezone;
> TimeZone
> ----------
> UTC+02
>
> SELECT * FROM tstest;
>           d
> ------------------------
> 2009-03-08 23:00:00-02
> 2009-06-12 00:00:00-02
> (2 rows)
>
> So - it's showing the timestamp with timezones you mentioned but in the
> current timezone. The UTC+02 actually being a -02 offset is just part of the
> standards afaik. Note that midnight 2009-03-09 is 2009-03-08 in the current
> timezone.
>

SELECT datetime FROM table ORDER BY datetime DESC LIMIT 1;
         datetime
------------------------
  2009-06-21 14:54:00+02

So it should also be +02 at your test. Why is it -02 at your test?

BTW:
2009-03-09 and 2009-03-08 are both in CET timezone in Europe (see above).

> So - if we run EXPLAIN on your queries that should show us how the values are
> getting typecast.
>
> => EXPLAIN SELECT * FROM tstest WHERE d >= '2009-03-09 00:00:00.0' AND d <
> '2009-03-10 00:00:00.0';
>                                                             QUERY PLAN
>
------------------------------------------------------------------------------------------------------------------------------------
> Seq Scan on tstest  (cost=0.00..42.10 rows=11 width=8)
>   Filter: ((d >= '2009-03-09 00:00:00-02'::timestamp with time zone) AND (d
> < '2009-03-10 00:00:00-02'::timestamp with time zone))
>
>
> This comes back with zero rows because without an explicit timezone it
> assumes our current one.
>
>
> => EXPLAIN SELECT * FROM tstest WHERE d >= '2009-06-12 00:00:00.0' AND d <
> '2009-06-13 00:00:00.0';
>                                                             QUERY PLAN
>
------------------------------------------------------------------------------------------------------------------------------------
> Seq Scan on tstest  (cost=0.00..42.10 rows=11 width=8)
>   Filter: ((d >= '2009-06-12 00:00:00-02'::timestamp with time zone) AND (d
> < '2009-06-13 00:00:00-02'::timestamp with time zone))
>
> This will match one row.
>
> Repeating the EXPLAIN on your other queries should show you what's happening.
> If I've missed the point of your question, can you say what results you get
> and what you think they should be.
>

See above.

For completeness:
--------------------------------------------------
       datetime >= TIMESTAMP WITHOUT TIME ZONE '2009-03-09 00:00:00.0'
   AND datetime  < TIMESTAMP WITHOUT TIME ZONE '2009-03-10 00:00:00.0'
-- Index Cond: ((datetime >= '2009-03-09 00:00:00'::timestamp without time zone) AND (datetime < '2009-03-10
00:00:00'::timestampwithout time zone)) 

=> Afterwars an implicit conversation to timestamp with time zone with the
timezone from the timestamp to be converted is done. (See my "docs"
above).

--------------------------------------------------
       datetime >= TIMESTAMP WITH TIME ZONE '2009-03-09 00:00:00.0'
   AND datetime  < TIMESTAMP WITH TIME ZONE '2009-03-10 00:00:00.0'
-- Index Cond: ((datetime >= '2009-03-09 00:00:00+01'::timestamp with time zone) AND (datetime < '2009-03-10
00:00:00+01'::timestampwith time zone)) 

--------------------------------------------------
       datetime >= TIMESTAMP WITHOUT TIME ZONE '2009-06-12 00:00:00.0'
   AND datetime  < TIMESTAMP WITHOUT TIME ZONE '2009-06-13 00:00:00.0'
--   Index Cond: ((datetime >= '2009-06-12 00:00:00'::timestamp without time zone) AND (datetime < '2009-06-13
00:00:00'::timestampwithout time zone)) 

Same as above.

--------------------------------------------------
       datetime >= TIMESTAMP WITH TIME ZONE '2009-06-12 00:00:00.0'
   AND datetime  < TIMESTAMP WITH TIME ZONE '2009-06-13 00:00:00.0'
--  Index Cond: ((datetime >= '2009-06-12 00:00:00+02'::timestamp with time zone) AND (datetime < '2009-06-13
00:00:00+02'::timestampwith time zone)) 


Ciao,
Gerhard

--
http://www.wiesinger.com/


Gerhard Wiesinger <lists@wiesinger.com> writes:
> Ok, the "problem" is:
> --------------------------------------------------
>        datetime >= '2009-03-09 00:00:00.0'
>    AND datetime  < '2009-03-10 00:00:00.0'
> -- Index Cond: ((datetime >= '2009-03-09 00:00:00+01'::timestamp with time zone) AND (datetime < '2009-03-10
00:00:00+01'::timestampwith time zone)) 
> --------------------------------------------------
>        datetime >= '2009-04-01 00:00:00.0'
>    AND datetime  < '2009-04-02 00:00:00.0'
> -- Index Cond: ((datetime >= '2009-04-01 00:00:00+02'::timestamp with time zone) AND (datetime < '2009-04-02
00:00:00+02'::timestampwith time zone)) 

> I would have expected that the 1st conversion is done with my current
> timezone of the query time (CEST=+02).

Well, it is being done with your current timezone ... but evidently with
a daylight-savings-time-aware definition of what that is.  If you really
want to dumb this down to not be DST aware, set your timezone setting
to a non-DST-aware value.  Perhaps the following will make it a bit
clearer what's happening:

regression=# set timezone to 'Europe/Vienna';
SET
regression=# select '2009-03-09 00:00:00.0'::timestamptz;
      timestamptz
------------------------
 2009-03-09 00:00:00+01
(1 row)

regression=# select '2009-04-01 00:00:00.0'::timestamptz;
      timestamptz
------------------------
 2009-04-01 00:00:00+02
(1 row)

regression=# set timezone to 'CEST-02';
SET
regression=# select '2009-03-09 00:00:00.0'::timestamptz;
      timestamptz
------------------------
 2009-03-09 00:00:00+02
(1 row)

regression=# select '2009-04-01 00:00:00.0'::timestamptz;
      timestamptz
------------------------
 2009-04-01 00:00:00+02
(1 row)

See here for more detail:
http://www.postgresql.org/docs/8.3/static/datatype-datetime.html#DATATYPE-TIMEZONES

            regards, tom lane