Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. 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. 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. So you can see how this will be a problem since there is no Feb-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. 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. 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. 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')
like image 350
sandsawks Avatar asked Nov 20 '25 02:11

sandsawks


1 Answers

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;
like image 153
Gordon Linoff Avatar answered Nov 21 '25 19:11

Gordon Linoff



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!