As a workaround, I could use this algorithm:
- Calculate
TargetDate1 target date using ADD_MONTHS . Alternatively, calculate the TargetDate2 date of TargetDate2 as follows:
1) apply ADD_MONTHS to the first of the source date dates;
2) Add the days difference between the source date and the beginning of the same month.
Choose LEAST between TargetDate1 and TargetDate2 .
Thus, at the end, the target date will contain another component of the day if the day component of the source date is greater than the number of days in the target month. In this case, the end date will be the last day of the corresponding month.
I'm not sure about my Oracle SQL syntaxes, but basically the implementation might look like this:
SELECT LEAST( ADD_MONTHS(SourceDate, Months), ADD_MONTHS(TRUNC(SourceDate, 'MONTH'), Months) + (SourceDate - TRUNC(SourceDate, 'MONTH')) ) AS TargetDate FROM ( SELECT TO_DATE('30-NOV-10', 'DD-MON-RR') AS SourceDate, 4 AS Months FROM DUAL )
Below is detailed information on how this method works:
SourceDate = '30-NOV-10' Months = 4 TargetDate1 = ADD_MONTHS('30-NOV-10', 4) = '31-MAR-11' TargetDate2 = ADD_MONTHS('01-NOV-10', 4) + (30 - 1) = '01-MAR-11' + 29 = '30-MAR-11' TargetDate = LEAST('31-MAR-11', '30-MAR-11') = '30-MAR-11'
And here are some more examples to show different cases:
SourceDate | Months | TargetDate1 | TargetDate2 | TargetDate -----------+--------+-------------+-------------+----------- 29-NOV-10 | 4 | 29-MAR-11 | 29-MAR-11 | 29-MAR-11 30-MAR-11 | -4 | 30-NOV-10 | 30-NOV-10 | 30-NOV-10 31-MAR-11 | -4 | 30-NOV-10 | 01-DEC-10 | 30-NOV-10 30-NOV-10 | 3 | 28-FEB-11 | 02-MAR-11 | 28-FEB-11
Andriy m
source share