Buenas senhoritos e senhoritas.

Neste pequeno post, vou mostrar como alterar o horário do servidor (Linux) e refletir isto no Oracle. Tarefa que faz muitos administradores odiarem o horário de verão 🙂
Na realidade, partindo da versão 10g pra frente, o Oracle atualiza automaticamente o horário ao se alterar o servidor. Porém para bases 9i ou anteriores, você deverá reiniciar o banco para pegar as alterações.

Alterando o horário do servidor

No exemplo abaixo, utilizarei o Oracle 10gr2 num Redhat.

Nosso horário:

SQL> alter session set NLS_DATE_FORMAT = 'dd/mm/yyyy HH24:mi:ss';
select sysdate from dual;
!date

Session altered.
SQL> 
SYSDATE
-------------------
19/10/2012 11:17:35
SQL> 
Sex Out 19 11:17:35 EDT 2012

Observe que o horário está ok tanto no oracle quanto no sistema operacional. Agora, vamos manter a sessão ativa e vamos alterar o horário do servidor.

[root@ora1 ~]# date -s 12:10
Sex Out 19 12:10:00 EDT 2012

E agora se formos na nossa sessão que ficou ativa, teremos:

SQL> select sysdate from dual;

SYSDATE
-------------------
19/10/2012 12:10:27

SQL>

Sem segredo, sem problemas. Neste caso.

Agora vamos a alguns problemas conhecidos de horário no Oracle.

1-Alterando o /etc/localtime

Pois bem, quando mudamos nosso localtime para apontar para uma nova zoneinfo, certamente teremos problemas na mudança de horários do Oracle.
Observe o que fiz com meu usuário ROOT:

[root@ora1 etc]# ln -s /usr/share/zoneinfo/Singapore /etc/localtime
[root@ora1 etc]# date
Sáb Out 20 00:20:31 SGT 2012

E como ficou meu usuário no Oracle ( aquele que estava logado )?

SQL> alter session set NLS_DATE_FORMAT = 'dd/mm/yyyy HH24:mi:ss';
select sysdate from dual;
!date
Session altered.

SQL> 
SYSDATE
-------------------
19/10/2012 12:23:15

SQL> 
Sex Out 19 12:23:16 EDT 2012

O horário exibido pelo oracle ainda é o antigo.

Como resolver?
Simples, reinicie a aplicação que usa o Oracle. Pois ela está com a config de zona antiga.

SQL> SELECT SESSIONTIMEZONE FROM DUAL;

SESSIONTIMEZONE
---------------------------------------------------------------------------
-04:00

Após reiniciar o aplicativo ou iniciar uma nova sessão:

SQL> SELECT SESSIONTIMEZONE FROM DUAL;

SESSIONTIMEZONE
---------------------------------------------------------------------------
+08:00
SQL> alter session set NLS_DATE_FORMAT = 'dd/mm/yyyy HH24:mi:ss';
select sysdate from dual;
Session altered.

SQL> 

SYSDATE
-------------------
20/10/2012 00:26:24

2-Variáveis de ambiente TZ!

É normal alguns administradores exportarem ou copiarem scripts de login ( profile ) entre os servidores. O problema é se o script setar a variável TZ incorretamente.
Observe que no env do usuário oracle, ( aqueeeele que tava logado ) não possuia a variável TZ.

[oracle@ora1 bdump]$ env | grep TZ
[oracle@ora1 bdump]$

Agora vamos exportar um TZ e ver o que acontece com nosso horário:

[oracle@ora1 bdump]$ export TZ='GMT-10'
[oracle@ora1 bdump]$ sqlplus -s / as sysdba
alter session set NLS_DATE_FORMAT = 'dd/mm/yyyy HH24:mi:ss';
select sysdate from dual;
Session altered.

SYSDATE
-------------------
20/10/2012 02:42:52

A data passou a ser 2h ao invés de 12.

Como resolver?
Basta remover o TZ ( export -n TZ ) ou setá-lo para refletir seu TIMEZONE atual, ou alterar a variável TIME_ZONE para refletir seu TIMEZONE.
alter session set TIME_ZONE=’-03:00′;