最近的这篇文章让我忙于调查 Oracle 中的儒略日期转换,并且我发现了我认为是 Oracle 11.1 中的一个错误。测试用例是:
案例1.
SELECT TO_CHAR(TO_TIMESTAMP('0', 'J'), 'DD MON SYYYY') FROM DUAL
这应该返回“01 JAN -4713”,如此处所定义,但会引发错误
ORA-01854: julian date must be between 1 and 5373484
案例2.
SELECT TO_CHAR(TO_TIMESTAMP('1', 'J'), 'DD MON SYYYY') FROM DUAL
这应该返回“02 JAN -4713”作为上述内容的扩展(比儒略零日期晚一天),但返回“01 JAN -4712”(相差不到一年的一天)。
案例3.
SELECT TO_CHAR(TO_TIMESTAMP('1721424', 'J'), 'DD MON SYYYY') FROM DUAL
返回“01 JAN 0001”。没关系(就目前而言)。如果我们从上面的日期值中减去 1,我们期望它返回前一天,即 31 DEC -0001(零年不存在);但是,当我们执行以下命令时
SELECT TO_CHAR(TO_TIMESTAMP('1721423', 'J'), 'DD MON SYYYY') FROM DUAL
抛出以下错误:
ORA-01841: (full) year must be between -4713 and +9999, and not be 0
表明 Oracle 已尝试生成零年份。
(请注意,虽然上面的测试用例中使用了 TO_TIMESTAMP,但使用 TO_DATE 时也会出现完全相同的问题)。
有谁知道吗
分享并享受。
根据下面 Phil 的回答,这些问题在 11.2 中仍然出现。
克苏鲁 fhtagn。
10.2.0.4 中的相同错误
当尝试了解 Oracle 应该做什么时,请查看 Oracle 的文档,“儒略日数是自公元前 4712 年 1 月 1 日以来的天数。”
该措辞确实暗示儒略日 1 是自公元前 4712 年 1 月 1 日以来的一天,换句话说,1 月 2 日。然而,儒略日期计算的当前实现已经存在很长时间了,现有代码取决于行为。 (我知道,如果 Oracle 中实现的 Julian 定义发生变化,我们就会完蛋。)此时,自公元前 4713 年 12 月 31 日以来最多只是一个文档错误。
编辑在调用接口程序员指南中找到了Julian 1为1月1日的参考。不是普通数据库程序员会看的地方。
以下解释维基百科和Oracle之间的年份差异:
Oracle数据库使用计算儒略的天文系统 天,其中公元前 4713 年被指定为 -4712。历史的 相反,计算儒略日的系统将 4713 BC 指定为 -4713。如果您将 Oracle 儒略日与使用历史系统计算的值进行比较,请注意考虑 365 天 BC 日期的差异。有关更多信息,请参阅 http://www.usno.navy.mil/USNO/astronomical-applications/astronomical-information-center/millennium.
案例 3 对我来说是新闻。谢谢你提出来。我不知道有任何涉及该行为的参考资料。相关:
SQL> select to_date('0001-01-01', 'YYYY-MM-DD')
- to_date ('-0001-12-31', 'SYYYY-MM-DD') from dual;
TO_DATE('0001-01-01','YYYY-MM-DD')-TO_DATE('-0001-12-31','SYYYY-MM-DD')
-----------------------------------------------------------------------
367
和
SQL> select months_between(to_date('0001-01-01', 'YYYY-MM-DD')
2 , to_date ('-0001-12-31', 'SYYYY-MM-DD')) from dual;
MONTHS_BETWEEN(TO_DATE('0001-01-01','YYYY-MM-DD'),TO_DATE('-0001-12-31','SYYYY-MM-DD'))
---------------------------------------------------------------------------------------
12.0322581
显然不存在的0年是闰年。
这是在 11.2.0.1.0 上执行的相同查询:
PHIL@PHILL11G2 > select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
Elapsed: 00:00:00.04
PHIL@PHILL11G2 > SELECT TO_CHAR(TO_TIMESTAMP('0', 'J'), 'DD MON SYYYY') FROM DUAL;
SELECT TO_CHAR(TO_TIMESTAMP('0', 'J'), 'DD MON SYYYY') FROM DUAL
*
ERROR at line 1:
ORA-01854: julian date must be between 1 and 5373484
Elapsed: 00:00:00.00
PHIL@PHILL11G2 > SELECT TO_CHAR(TO_TIMESTAMP('1', 'J'), 'DD MON SYYYY') FROM DUAL;
TO_CHAR(TO_T
------------
01 JAN -4712
Elapsed: 00:00:00.00
PHIL@PHILL11G2 > SELECT TO_CHAR(TO_TIMESTAMP('1721424', 'J'), 'DD MON SYYYY') FROM DUAL;
TO_CHAR(TO_T
------------
01 JAN 0001
Elapsed: 00:00:00.00
PHIL@PHILL11G2 > SELECT TO_CHAR(TO_TIMESTAMP('1721423', 'J'), 'DD MON SYYYY') FROM DUAL;
SELECT TO_CHAR(TO_TIMESTAMP('1721423', 'J'), 'DD MON SYYYY') FROM DUAL
*
ERROR at line 1:
ORA-01841: (full) year must be between -4713 and +9999, and not be 0
Elapsed: 00:00:00.04
PHIL@PHILL11G2 >