3

最近的这篇文章让我忙于调查 Oracle 中的 Julian 日期转换,并且我发现了我认为是 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 时会出现完全相同的问题)。

有谁知道如果

  1. Oracle 已经记录了这些问题?
  2. 这些问题在11.2还存在吗?

分享和享受。


根据 Phil 在下面的回答,这些问题仍然出现在 11.2 中。

克苏鲁fhtagn。


10.2.0.4 中的相同错误

4

3 回答 3

2

在尝试了解 Oracle 应该做什么时,请查看 Oracle 的文档,“儒略日数是自公元前 4712 年 1 月 1 日以来的天数。”

该措辞确实暗示儒略 1 将是自公元前 4712 年 1 月 1 日起的一天,即 1 月 2 日。然而,儒略日期计算的当前实现已经存在了很长时间,现有代码取决于行为. (我知道如果在 Oracle 中实现的 Julian 的定义发生变化,我们会被搞砸的。)在这一点上,自公元前 4713 年 12 月 31 日以来的几天最多只是一个文档错误。

编辑在Call Interface Programmer's Guide中找到了Julian 1的参考资料,即 1 月 1 日。不是普通数据库程序员会看到的地方。

以下解释了维基百科和 Oracle 之间的年份差异:

Oracle 数据库使用计算儒略日的天文系统,其中公元前 4713 年指定为 -4712。相比之下,计算儒略日的历史系统将公元前 4713 年指定为 -4713。如果您将 Oracle Julian 天数与使用历史系统计算的值进行比较,请注意考虑到 BC 日期的 365 天差异。如需更多信息,请参阅 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 年是闰年。

于 2012-05-03T19:10:11.727 回答
1

以下是在 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 > 
于 2012-05-03T12:58:50.040 回答
0

美国海军天文台修改朱利安日期

于 2013-06-29T08:09:35.297 回答