ORA-01848:一年中的某一天必须介于1到365之间(闰年为366)错误

时间:2018-01-17 10:00:02

标签: sql oracle date julian-date

我有以DDD格式存储的一年中(1-366)的现有数据。

现在,当我尝试查询数据并以MM / DD / YYYY格式提取报告时,我正在获取 ORA-01848: day of year must be between 1 and 365 (366 for leap year)用于以下查询

select to_CHAR(TO_DATE(MyColumn, 'DDD'),'MM/DD/YYYY') from MyTable;

当年份为闰年时,如何以MM / DD / YYYY格式检索日期?

2 个答案:

答案 0 :(得分:4)

您当前的疑问:

select to_CHAR(TO_DATE(MyColumn, 'DDD'),'MM/DD/YYYY') from MyTable;

默认为当年。所有转换后的值都将显示2018:

-- CTE for dummy values (<= 365)
with mytable(mycolumn) as (
  select 1 from dual
  union all select 60 from dual
  union all select 365 from dual
)
select to_CHAR(TO_DATE(MyColumn, 'DDD'),'MM/DD/YYYY') from MyTable;

TO_CHAR(TO
----------
01/01/2018
03/01/2018
12/31/2018

由于2018年不是闰年,因此第366天无效。您可以使用任意硬编码的闰年:

select to_CHAR(TO_DATE('2000' || MyColumn, 'YYYYDDD'),'MM/DD/YYYY') from MyTable;

演示:

-- CTE for dummy values
with mytable(mycolumn) as (
  select 1 from dual
  union all select 60 from dual
  union all select 365 from dual
  union all select 366 from dual
)
select to_CHAR(TO_DATE('2000' || MyColumn, 'YYYYDDD'),'MM/DD/YYYY') from MyTable;

TO_CHAR(TO
----------
01/01/2000
02/29/2000
12/30/2000
12/31/2000

但是,如果原始日期不是从闰年开始,那么这些数值将会在一天之内出现 - 当然也会在错误的一年显示出来。

您可以使用值&gt;过滤掉值365并坚持到今年,但你又可能会得到不切实际/无益的转换日期。或者您可以使用12c的default ... on conversion error语法在无法转换时获得空结果,但其他日期也会不一致。

除非您知道每个DDD值代表的年份,否则您无法获得准确的转化​​。

如果您有另一列保存年份,则将它们连接在一起,例如如果该年份列被称为MyYear

select to_CHAR(TO_DATE(MyYear || MyColumn, 'YYYYDDD'),'MM/DD/YYYY') from MyTable;

演示显示不同的结果:

-- CTE for dummy values
with mytable(mycolumn, myyear) as (
  select 1, 2018 from dual
  union all select 60, 2016 from dual
  union all select 60, 2017 from dual
  union all select 365, 2016 from dual
  union all select 366, 2016 from dual
  union all select 365, 2017 from dual
)
select MyColumn, MyYear,
  to_CHAR(TO_DATE(MyColumn default null on conversion error, 'DDD'),'MM/DD/YYYY') as Y2018,
  to_CHAR(TO_DATE('2000' || MyColumn, 'YYYYDDD'),'MM/DD/YYYY') as Y2000,
  to_CHAR(TO_DATE(MyYear || MyColumn, 'YYYYDDD'),'MM/DD/YYYY') as OK
from MyTable;

  MYCOLUMN     MYYEAR Y2018      Y2000      OK        
---------- ---------- ---------- ---------- ----------
         1       2018 01/01/2018 01/01/2000 01/01/2018
        60       2016 03/01/2018 02/29/2000 02/29/2016
        60       2017 03/01/2018 02/29/2000 03/01/2017
       365       2016 12/31/2018 12/30/2000 12/30/2016
       366       2016            12/31/2000 12/31/2016
       365       2017 12/31/2018 12/30/2000 12/31/2017

答案 1 :(得分:1)

我创建了一个逻辑,可根据输入日计算日期。当它不是闰年时,它会显示日期。如果天数为366,如果闰年显示最后一天。如果它不是闰年,如果天数为366,它将显示一年中的最后一天,因此它永远不会导致您遇到的错误。

with tb(col1) as (Select level 
                  from dual
                  connect by level < 367)
-- Actual Query ..Col1 is the day number being passed.                                                    
Select  Case when col1 < 366 then
        to_char(TO_DATE(col1, 'DDD'),'MM/DD/YYYY') 
        else
         to_char(LAST_DAY(ADD_MONTHS(TRUNC(SYSDATE , 'Year'),11)),'MM/DD/YYYY')
        end col
from tb ;

DEMO