Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Oracle timestamp com tradução transparente de valores de fuso horário local


TIMESTAMP WITH LOCAL TIME ZONE funciona assim:Quando você precisa trabalhar com fusos horários em seu aplicativo, uma abordagem comum é

É exatamente assim que TIMESTAMP WITH LOCAL TIME ZONE funciona - a única diferença é

Por esse motivo, você não pode alterar DBTIMEZONE (com ALTER DATABASE SET TIME_ZONE='...'; ) em seu banco de dados se o banco de dados contiver uma tabela com um TIMESTAMP WITH LOCAL TIME ZONE coluna e a coluna contém dados.

SYSTIMESTAMP é retornado no fuso horário do sistema operacional do servidor de banco de dados. DBTIMEZONE é não o fuso horário de SYSTIMESTAMP ou SYSDATE .

DBTIMEZONE define o formato de armazenamento interno de TIMESTAMP WITH LOCAL TIME ZONE colunas de tipo de dados. Esqueça isso, não consigo imaginar nenhum caso de uso em que você precise.

Na verdade sua tabela é equivalente a este select:
select 
   CAST(systimestamp AS timestamp(0) with local time zone) as SYSTIMESTAMP_COL,
   CAST(sysdate AS timestamp(0) with local time zone) as SYSDATE_COL,
   CAST(current_timestamp AS timestamp(0) with local time zone) as CURRENT_TIMESTAMP_COL,
   CAST(timestamp '2017-03-15 19:02:00' AS timestamp(0) with local time zone) as DATE_COL
from dual;

Quando você faz CAST({time without time zone} with local time zone) em seguida, você tenta converter um valor de data/hora sem nenhuma informação de fuso horário em um valor de data/hora com fuso horário. Em princípio, isso não é possível porque o Oracle não possui as informações de fuso horário, portanto, o Oracle assume um fuso horário. Se você fizer essa conversão, a Oracle sempre considerará {time without time zone} conforme fornecido em SESSIONTIMEZONE (no momento da conversão).

Então CAST(sysdate AS timestamp(0) with local time zone) é equivalente a
CAST(FROM_TZ(TO_TIMESTAMP(SYSDATE), SESSIONTIMEZONE) AS TIMESTAMP(0) WITH LOCAL TIME ZONE)` 

resp. CAST(timestamp '2017-03-15 19:02:00' AS timestamp(0) with local time zone) significa
CAST(FROM_TZ(TIMESTAMP '2017-03-15 19:02:00', SESSIONTIMEZONE) AS TIMESTAMP(0) WITH LOCAL TIME ZONE)

Para SYSDATE isso está realmente errado, porque SYSDATE é fornecido no fuso horário do sistema operacional do servidor de banco de dados e não em SESSIONTIMEZONE. Para o segundo depende da sua intenção se o resultado está correto ou não.

SYSTIMESTAMP retorna o valor TIMESTAMP WITH TIME ZONE , é sempre independente do seu SESSIONTIMEZONE atual . Mas se você converter para TIMESTAMP WITH LOCAL TIME ZONE ele é convertido para o seu fuso horário local atual, é claro. Você também pode usar CURRENT_TIMESTAMP ou SYSTIMESTAMP AT LOCAL que faz mais ou menos o mesmo.

Este código

parece estar errado. O resultado deve ser
-- SYSTIMESTAMP_COL                   15/03/2017 16:01:14
-- SYSDATE_COL                        15/03/2017 19:01:14
-- CURRENT_TIMESTAMP_COL              15/03/2017 16:01:14
-- DATE_COL                           15/03/2017 19:02:00

As diferenças parecem como deveriam ser, mas os valores absolutos parecem ser "falsificados" (ou há um problema real com seu banco de dados).