简体   繁体   English

ORA-01839:日期对指定的月份无效,如何避免闰年问题

[英]ORA-01839: date not valid for month specified, How to avoid leap year issues

I have a table that stores a valid "custom date" for each person. 我有一个表,为每个人存储有效的“自定义日期”。 That date may legitimately be Feb 29 of a leap year. 那个日期可能合法地是闰年的2月29日。 The thing is in my SQL for my report I need to pull the "last" mm/dd for from this custom date field for that employee as of the most recent year. 事情是在我的SQL报告中,我需要从最近一年的该员工的自定义日期字段中提取“最后一个”mm / dd。 This date is never in the future so I can compare the year in the date and if its the current year pull it as is. 这个日期永远不会在将来,所以我可以比较日期中的年份,如果它的当前年份拉它原样。 However if it's any previous year (can go back as far as 1900) I need to instead pull that MM/DD and as of last year. 然而,如果它是前一年(可以追溯到1900年),我需要取而代之的是去年的MM / DD。 So you can see how this will be a problem since there is no Feb-29-2018. 所以你可以看到这将是一个问题,因为没有2月29日至2018年。

I'm looking for the best solution on how to handle this. 我正在寻找如何处理这个问题的最佳解决方案。 I need it in my select portion and my conditional block where this date I'm trying to derive has to be >= the applydtm date. 我需要它在我的选择部分和我的条件块中,我想要得出的这个日期必须> = applydtm日期。 Here is a sample query to replicate the error. 以下是复制错误的示例查询。 Simply switching the Feb-29 date to Feb-28 will show it working since it doesn't encounter that invalid leap year date. 简单地将2月29日的日期切换到2月28日将显示它正在工作,因为它没有遇到无效的闰年日期。 I would be okay with all Feb 29 dates 'converting' to Mar 1st if need be as long as the code is efficient as possible. 如果需要的话,只要代码尽可能高效,我可以将2月29日的所有日期“转换”到3月1日。 DB = Oracle 11g DB = Oracle 11g

WITH sampledata (actualcustomdtm, textfield, applydtm)  AS  (
SELECT
TO_DATE('02/29/2012 00:00:00','mm/dd/yyyy hh24:mi:ss'),
'Leap Year',
sysdate
FROM dual
UNION
SELECT
TO_DATE('01/15/2019 00:00:00','mm/dd/yyyy hh24:mi:ss'),
'Non-Leap Year',
sysdate
FROM dual
)
SELECT
actualcustomdtm,
CASE WHEN TO_CHAR(actualcustomdtm, 'YYYY') = TO_CHAR(SYSDATE, 'YYYY')
     THEN TO_CHAR(actualcustomdtm, 'MM/DD/YYYY')
     ELSE TO_CHAR(actualcustomdtm, 'MM/DD')||'/'||TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -12), 'YYYY')
     END AS "LASTACTCSTMDATE",
textfield,
applydtm
FROM sampledata
WHERE applydtm >=
    TO_DATE(CASE WHEN TO_CHAR(actualcustomdtm, 'YYYY') = TO_CHAR(SYSDATE, 'YYYY')
    THEN TO_CHAR(actualcustomdtm, 'MM/DD/YYYY')
    ELSE TO_CHAR(actualcustomdtm, 'MM/DD')||'/'||TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -12), 'YYYY')
    END, 'MM/DD/YYYY')

I believe this logic does what you want -- getting the most recent anniversary up to or including today's date: 我相信这种逻辑符合你的要求 - 将最近的纪念日纳入或包括今天的日期:

select dte, add_months(dte, 12),
       (case when to_char(dte, 'MMDD') > to_char(sysdate, 'MMDD')
             then add_months(dte, 12 * (extract(year from sysdate) - extract(year from dte) - 1))
             else add_months(dte, 12 * (extract(year from sysdate) - extract(year from dte)))
        end)
from (select date '2016-02-29' as dte from dual union all
      select date '2018-01-03' from dual
     ) x;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM