到了_YY,yyyy给了我不同的结果

时间:2017-05-06 23:01:36

标签: plsql oracle11g

如果我运行以下查询

  

从双重选择to_char(TO_DATE(SYSDATE-7,'DD / MM / YY'),'年')

结果是二十七岁

  

从双重选择to_char(TO_DATE(SYSDATE-7,'DD / MM / YYYY'),'年')

结果是十七岁

为什么我第二次查询得不到二十七?

2 个答案:

答案 0 :(得分:3)

因为您正在进行从字符串到日期的不必要的显式转换,这是根据您的NLS设置从日期到字符串执行隐式转换。

你应该做的只是:

select to_char(sysdate - 7, 'year') from dual;

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

由于sysdate-7已经是日期,因此您不应该使用任何格式调用to_date()。由于to_date()函数采用字符串参数,因此必须首先将sysdate-7表达式隐式转换为字符串。所以你真的在做:

select to_char(to_date(to_char(sysdate - 7), 'DD/MM/YYYY'), 'year') from dual;

正在使用您的NLS_DATE_FORMAT值进行隐式内部to_char()调用,所以如果是'DD-MON-RR',那么您实际上是这样做的:

select to_char(to_date(to_char(sysdate - 7, 'DD-MON-RR'), 'DD/MM/YYYY'), 'year') from dual;

要查看那里发生了什么,您需要查看完整生成日期的内容,因此我将更改会话的NLS_DATE_FORMAT以显示全年:

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

注意最后两个值中的不同年份。 The documentation has a section on format model matching。您在中间隐式创建的字符串具有2位数年份。当您使用'30-APR-17'模型将字符串YY转换回日期时,它'有助于'假设当前世纪,因此日期最终结束为2017年。但是当您使用{转换相同的字符串时{1}}模型,它认为你真的意味着你传递的价值,所以不假设一个世纪 - 你通过它17,所以你最终得到17年;也就是0017而不是2017.(你也可以使用YYYY得到你期望的答案,但坚持RRRR并且实际上每个地方都使用4位数的年份要好得多 - 如果你实际上需要使用一个字符串。)

基本上:不依赖于NLS设置或将日期隐式转换为字符串,反之亦然。

在这种情况下,您不需要任何转换,因此请使用此答案顶部的更简单的声明。

答案 1 :(得分:0)

你应该获得2017年第二次查询,而不是1次查询。其他可能性是NLS设置或会话,软件设置。 除此之外,你必须使用' YYYY'而不是' YY'到2017年