与SYSDATE的日期差异 - 值给出了什么?

Har*_*hah 1 sql oracle plsql

当减去今天的日期时,给出正确的输出.

select 
    (TRUNC(to_date('25/05/2016','dd/mm/yyyy'))-TRUNC(to_date('02/01/2016','dd/mm/yyyy')))
from dual;
Run Code Online (Sandbox Code Playgroud)

输出:144天

当今天采取日期时,下面的广告sysdate应该给144.但是显示其他一些值?为什么?

select 
    (to_date(SYSDATE,'dd/mm/yyyy'))-(to_date('02/01/2016','dd/mm/yyyy'))
from dual;
Run Code Online (Sandbox Code Playgroud)

输出:-730343(显示一些值).

Ale*_*ole 5

当你这样做时:

to_date(SYSDATE,'dd/mm/yyyy')
Run Code Online (Sandbox Code Playgroud)

您使用NLS_DATE_FORMAT将SYSDATE(已经是日期)隐式转换为字符串.从似乎是DD-MON-RR的结果.所以你真的在做:

to_date(to_char(SYSDATE,'DD-MON-RR'),'dd/mm/yyyy')
Run Code Online (Sandbox Code Playgroud)

内部部分为您提供字符串'25 -MAY-16'.当你将它转换回带yyyy掩码的日期时,你有一个两位数的年份,16,这被解释为0016年而不是2016年.如果你用的话,你实际上会得到你所期望的rrrr,但这是一个愉快的副作用,它仍会在不同NLS设置的会话中中断:

select to_date(SYSDATE,'dd/mm/yyyy') as bad_nls,
  to_char(to_date(SYSDATE,'dd/mm/yyyy'), 'YYYY-MM-DD') as bad_string,
  to_date(SYSDATE,'dd/mm/rrrr') as ok_nls,
  to_char(to_date(SYSDATE,'dd/mm/rrrr'), 'YYYY-MM-DD') as ok_string
from dual;

BAD_NLS   BAD_STRING OK_NLS    OK_STRING
--------- ---------- --------- ----------
25-MAY-16 0016-05-25 25-MAY-16 2016-05-25
Run Code Online (Sandbox Code Playgroud)

请注意,使用当前的NLS掩码和隐式转换为字符串,您无法区分第一个和第三个结果; 但显而易见的是,在第二和第四个结果中以四位数年份显示出来是错误的.

通过隐式转换,您将0016-05-25与2016-01-02进行比较,并且它给出了-730343,因为它是2000年中的天数,根据您预期的差距144天进行了调整.

正如Praveen已经说过你不需要to_date()用于SYSDATE,如果你试图将时间部分设置为午夜,你可以截断它.

select date '2016-05-25' - date '2016-01-02' as diff1,
  date '2016-05-25' - date '0016-05-25' as diff2,
  date '0016-05-25' - date '2016-01-02' as diff3,
  trunc(sysdate) - date '2016-01-02' as diff4
from dual;

     DIFF1      DIFF2      DIFF3      DIFF4
---------- ---------- ---------- ----------
       144     730487    -730343        144
Run Code Online (Sandbox Code Playgroud)

但更一般地说,不要使用两位数年份(唉,似乎我们已经忘记了Y2K的教训!),并且不依赖于NLS设置.