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

TO_DATE yy,yyyy me dá resultados diferentes


Porque você está fazendo uma conversão explícita desnecessária de string para data, o que está fazendo um implícito conversão de data para string com base em suas configurações de NLS.

O que você deve fazer é apenas:
select to_char(sysdate - 7, 'year') from dual;

TO_CHAR(SYSDATE-7,'YEAR')                 
------------------------------------------
twenty seventeen

Porque sysdate-7 já é uma data, você não deveria estar chamando to_date() em torno disso, com qualquer formato. Como o to_date() função recebe um argumento de string, seu sysdate-7 expressão deve ser convertida implicitamente em uma string primeiro. Então você está realmente fazendo:
select to_char(to_date(to_char(sysdate - 7), 'DD/MM/YYYY'), 'year') from dual;

que está usando seu valor NLS_DATE_FORMAT para o to_char() interno implícito call, então se for dizer 'DD-MON-RR' você está realmente fazendo:
select to_char(to_date(to_char(sysdate - 7, 'DD-MON-RR'), 'DD/MM/YYYY'), 'year') from dual;

Para ver o que está acontecendo lá você precisa ver qual é a data completa gerada, então para isso vou alterar o NLS_DATE_FORMAT para a sessão mostrar o ano completo:
alter session set nls_date_format = 'SYYYY-MM-DD';

select sysdate - 7 as raw_date,
  to_char(sysdate - 7, 'DD-MON-RR') as implicit_string,
  to_date(to_char(sysdate - 7, 'DD-MON-RR'), 'DD/MM/YY') as implcit_yy,
  to_date(to_char(sysdate - 7, 'DD-MON-RR'), 'DD/MM/YYYY') as implcit_yyyy
from dual;

RAW_DATE    IMPLICIT_STRING    IMPLCIT_YY  IMPLCIT_YYY
----------- ------------------ ----------- -----------
 2017-04-30 30-APR-17           2017-04-30  0017-04-30

Observe os diferentes anos nos dois últimos valores. A documentação tem uma seção sobre correspondência de modelo de formato . A string que você está criando implicitamente no meio tem um ano de 2 dígitos. Quando você converte a string '30-APR-17' voltar para uma data usando um YY model, ele assume 'utilmente' o século atual, então a data termina em 2017. Mas quando você converte a mesma string usando um YYYY modelo ele acha que você realmente quis dizer o valor que você passou e então não assume um século - e você passou 17, então você acaba com o ano 17; ou seja, 0017 e não 2017. (Você também teria a resposta que esperava usando RRRR , mas é muito melhor ficar com YYYY e usar anos de 4 dígitos em todos os lugares - se você realmente precisa usar uma string.)

Essencialmente:não confie em configurações NLS ou conversões implícitas de datas em strings ou vice-versa.

Neste caso, você não precisa de nenhum conversões, então use a instrução mais simples na parte superior desta resposta.