如果我运行以下查询
从双重选择to_char(TO_DATE(SYSDATE-7,'DD / MM / YY'),'年')
结果是二十七岁
从双重选择to_char(TO_DATE(SYSDATE-7,'DD / MM / YYYY'),'年')
结果是十七岁
为什么我第二次查询得不到二十七?
答案 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年