【问题标题】:ORA-01848: day of year must be between 1 and 365 (366 for leap year) errorORA-01848: 一年中的某一天必须介于 1 和 365 之间(闰年为 366)错误
【发布时间】:2018-01-17 18:46:56
【问题描述】:

我有以 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 格式的日期?

【问题讨论】:

  • 并且没有列值> 365?
  • 在不知道 DDD 值代表的年份的情况下,您无法可靠地将其转换为完整日期。是否有另一列有年份?
  • @jarlh 有许多列值 > 365。这些是我收到 ORA-01848 错误的行。
  • @AlexPoole 是的,我注意到另一列有年份值。

标签: sql oracle date julian-date


【解决方案1】:

您当前的查询:

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

但是,如果原始日期不是闰年,那么这些值会相差一天——当然,也会显示错误的年份。

您可以过滤掉值 > 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

【讨论】:

    【解决方案2】:

    我创建了一个根据输入日期计算日期的逻辑。当它不是闰年时,它会显示日期。在闰年的情况下,如果天数是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

    【讨论】:

      猜你喜欢
      • 2020-09-07
      • 1970-01-01
      • 1970-01-01
      • 2017-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-17
      相关资源
      最近更新 更多