0
select sysdate
from dual;
日期
--------
2017 年 5 月 3 日
select sysdate -1 
from dual;
日期
--------
2017 年 5 月 2 日
===============

如果运行以下 sql 查询

select TO_DATE('01-DEC-15','DD-MON-YYYY') - 1
FROM DUAL;

我在 2015
年 11 月 30 日得到答案

===== 任何人都可以帮助我理解这种行为吗?

4

1 回答 1

0

该文档有一个关于日期时间/间隔算术的部分。添加到日期或从日期中减去的数字被视为一天的一小部分:

例如,SYSDATE + 1 是明天。SYSDATE - 7 是一周前。SYSDATE + (10/1440) 距离现在十分钟

正如@mathguy 指出的那样,Oracle 中的所有日期都有一个时间组件,并且sysdate具有当前服务器时间。如果您显示日期/时间的完整值,您可以看到发生了什么。您可以使用to_char()合适的格式显式执行此操作,但为了简洁起见,我将更改会话 NLS 设置:

alter session set nls_date_format = 'SYYYY-MM-DD HH24:MI:SS';

select sysdate, sysdate - 1
from dual;

SYSDATE              SYSDATE-1           
-------------------- --------------------
 2017-05-03 16:17:47  2017-05-02 16:17:47

两者都显示相同的时间,但在不同的日子。

您可以截断日期以降低其精度;默认情况下trunc(sysdate)将时间元素归零,因此它变成今天的午夜而不是当前时间。

您的第三个示例稍微有趣一些,因为您使用了不匹配的值和格式掩码;使用 2 位数的年份和 4 位数YYYY的掩码,年份不会像您预期的那样结束:

select to_date('01-DEC-15','DD-MON-YYYY'), to_date('01-DEC-15','DD-MON-YYYY') - 1
from dual;

TO_DATE('01-DEC-15', TO_DATE('01-DEC-15',
-------------------- --------------------
 0015-12-01 00:00:00  0015-11-30 00:00:00

那可能不是你想要的。RRRR面具更宽容,如手册中所述:

select to_date('01-DEC-15','DD-MON-RRRR'), to_date('01-DEC-15','DD-MON-RRRR') - 1
from dual;

TO_DATE('01-DEC-15', TO_DATE('01-DEC-15',
-------------------- --------------------
 2015-12-01 00:00:00  2015-11-30 00:00:00

但最好还是提供一个完整的 4 位数年份:

select to_date('01-DEC-2015','DD-MON-YYYY'), to_date('01-DEC-2015','DD-MON-YYYY') - 1
from dual;

TO_DATE('01-DEC-2015 TO_DATE('01-DEC-2015
-------------------- --------------------
 2015-12-01 00:00:00  2015-11-30 00:00:00

或者更简单地说,使用日期文字

select date '2015-12-01', date '2015-12-01' - 1
from dual;

DATE'2015-12-01'     DATE'2015-12-01'-1  
-------------------- --------------------
 2015-12-01 00:00:00  2015-11-30 00:00:00

这也避免了日期语言的问题;'APR'在语言 - 特别是 - 不是英语的会话中不会被识别NLS_DATE_LANGAUGE(除非它巧合地是另一种语言的公认缩写,但几个月仍然会失败)。最好使用月份数字。如果您必须使用名称或缩写,您可以使用可选的第三个参数来指定它们所在的语言to_date()。但是,如果您不从字符串变量转换,文字仍然更容易。

于 2017-05-03T15:28:15.250 回答