“AT TIME ZONE” com o nome da zona bug do PostgreSQL?

12

Eu estava respondendo a essa pergunta do stackoverflow e encontrei um resultado estranho:

 select * from  pg_timezone_names where name = 'Europe/Berlin' ;
     name      | abbrev | utc_offset | is_dst 
---------------+--------+------------+--------
 Europe/Berlin | CET    | 01:00:00   | f

e próxima consulta

select id, 
  timestampwithtimezone, 
  timestampwithtimezone at time zone 'Europe/Berlin' as berlin, 
  timestampwithtimezone at time zone 'CET' as cet 
from data ;
 id  | timestampwithtimezone  |       berlin        |         cet         
 -----+------------------------+---------------------+---------------------
 205 | 2012-10-28 01:30:00+02 | 2012-10-28 01:30:00 | 2012-10-28 00:30:00
 204 | 2012-10-28 02:00:00+02 | 2012-10-28 02:00:00 | 2012-10-28 01:00:00
 203 | 2012-10-28 02:30:00+02 | 2012-10-28 02:30:00 | 2012-10-28 01:30:00
 202 | 2012-10-28 02:59:59+02 | 2012-10-28 02:59:59 | 2012-10-28 01:59:59
 106 | 2012-10-28 02:00:00+01 | 2012-10-28 02:00:00 | 2012-10-28 02:00:00

Estou usando o PostgreSQL 9.1.2 e o ubuntu 12.04.
Apenas verifiquei que no resultado 8.2.11 é o mesmo.

De acordo com a documentação , não importa se eu uso nome ou abreviação.

Isso é um inseto?
Estou fazendo algo errado?
Alguém pode explicar esse resultado?

EDIT Pelo comentário de que a CET não é a Europa / Berlim.

Estou apenas selecionando valores de pg_timezone_names.

select * from  pg_timezone_names  where abbrev ='CEST';
 name | abbrev | utc_offset | is_dst 
------+--------+------------+--------

e

select * from  pg_timezone_names  where abbrev ='CET';
        name         | abbrev | utc_offset | is_dst 
---------------------+--------+------------+--------
 Africa/Tunis        | CET    | 01:00:00   | f
 Africa/Algiers      | CET    | 01:00:00   | f
 Africa/Ceuta        | CET    | 01:00:00   | f
 CET                 | CET    | 01:00:00   | f
 Atlantic/Jan_Mayen  | CET    | 01:00:00   | f
 Arctic/Longyearbyen | CET    | 01:00:00   | f
 Poland              | CET    | 01:00:00   | f
 .....

Durante o inverno, a Europa / Berlim é +01. Durante o verão é +02.

EDIT2 Em 28/10/2012, o fuso horário mudou de horário de verão para o inverno às 2:00.
Esses dois registros têm o mesmo valor na Europa / Berlim:

204 | 2012-10-28 02:00:00+02 | 2012-10-28 02:00:00 | 2012-10-28 01:00:00
106 | 2012-10-28 02:00:00+01 | 2012-10-28 02:00:00 | 2012-10-28 02:00:00

Isso sugere que, se eu usar uma das abreviações (CET ou CEST) para o resultado do grande intervalo de dados (horário de verão e inverno), estará errado para alguns dos registros. Vai ser bom se eu usar 'Europa / Berlim'.

Alterei a hora do sistema para '2012-01-17' e pg_timezone_names também mudou.

select * from  pg_timezone_names  where name ='Europe/Berlin';
     name      | abbrev | utc_offset | is_dst 
---------------+--------+------------+--------
 Europe/Berlin | CEST   | 02:00:00   | t
suficiente
fonte
1
É certo que 2012-10-28 01:30:00é CEST, não CET.
dezso '
1
Tanto quanto eu sei que nãoCET é - pelo menos não durante os horários de verão. Europe/Berlin
A_horse_with_no_name 20/12/12

Respostas:

9

Na verdade, a documentação diz claramente que o nome e a abreviação do fuso horário se comportarão de maneira diferente.

Em resumo, esta é a diferença entre abreviações e nomes completos: as abreviações sempre representam um deslocamento fixo do UTC, enquanto a maioria dos nomes completos implica uma regra local de horário de verão e, portanto, tem dois possíveis desvios do UTC. Referência

FWIW, essa mesma referência também diz

Não recomendamos o uso do tipo hora com fuso horário (embora seja suportado pelo PostgreSQL para aplicativos herdados e para conformidade com o padrão SQL).

Mike Sherrill 'Recolha de gatos'
fonte
6

E essa ainda não é a essência! Eu encontrei um problema muito semelhante há algum tempo.

Os principais contras das abreviações de fuso horário já foram apresentados aqui: eles não levam em consideração o horário de verão. O principal profissional: simplicidade, resultando em desempenho superior . A consideração das regras de horário de verão torna os nomes dos fusos horários lentos em comparação. As abreviações de fuso horário são compensações simples e simbólicas, os nomes dos fusos horários estão sujeitos a um conjunto de regras em constante mudança. Fiz benchmarks nesta resposta relacionada ao SO , a diferença é notável. Mas quando aplicado a um conjunto, normalmente é necessário usar nomes de fuso horário para cobrir possíveis status diferentes de horário de verão por linha (e também diferenças históricas).

Estamos falando de CET . A parte realmente complicada é que "CET" não é apenas (obviamente) uma abreviação de fuso horário , é também um nome de fuso horário , pelo menos de acordo com a minha instalação (PostgreSQL 9.1.6 no Debian Squeeze com o código de idioma "de_AT.UTF-8 ") e todos os outros que vi até agora. Menciono esses detalhes, porque o Postgres usa as informações de localidade do SO subjacente, se disponíveis.

Veja por si mesmo:

SELECT * FROM pg_timezone_names WHERE name = 'CET';

SELECT * FROM pg_timezone_abbrevs WHERE abbrev = 'CET';

SQL Fiddle.

O Postgres seleciona a abreviação sobre o nome completo. Portanto, embora eu tenha encontrado CET nos nomes de fuso horário , a expressão '2012-01-18 01:00 CET'::timestamptzé interpretada de acordo com as regras sutilmente diferentes para abreviações de fuso horário .

Se não é uma espingarda carregada, não sei o que é.

Para evitar ambiguidades, vá com o nome do fuso horário 'Europa / Berlim' (ou 'Europa / Viena' no meu caso - que é efetivamente o mesmo, exceto por diferenças históricas). Encontre mais detalhes sobre o tópico na pergunta intimamente relacionada que mencionei acima .

Para encerrar, gostaria de expressar meu profundo desprezo pelo conceito idiota do horário de verão. Deve ser removido da existência e nunca mais se fala.

Erwin Brandstetter
fonte
3

Verifique isto:

select  
    '2012-10-28 02:30:00+02'::timestamp with time zone at time zone 'Europe/Berlin' as berlin,
    '2012-10-28 02:30:00+02'::timestamp with time zone at time zone 'CET' as cet,
    '2012-10-28 02:30:00+02'::timestamp with time zone at time zone 'CEST' as cest

+02 é CEST em Berlim, não CET.

dezso
fonte