Reputation: 1298
Oracle: 12c
Description: Trying to add 99 years to a date using add_months, which works however it adds an additional day to the return date value. How should i properly add years to a date?
declare
toRetDate DATE;
inputDate DATE;
numYears number;
begin
numYears := 99;
inputDate := TO_DATE('28-FEB-85', 'DD-Mon-YY' );
toRetDate := add_months(inputDate, numYears*12);
DBMS_OUTPUT.put_line(toRetDate);
end;
Output:29-FEB-84
Upvotes: 2
Views: 3158
Reputation: 9886
You can use this way:
declare
toRetDate DATE;
inputDate DATE;
numYears number;
begin
numYears := 99;
inputDate := TO_DATE('28-FEB-1985', 'DD-Mon-YYYY' );
toRetDate := inputDate + INTERVAL '99' YEAR; --add_months(inputDate, numYears*12);
DBMS_OUTPUT.put_line(to_date(toRetDate,'dd-mon-yyyy'));
end;
Although it's worth noting that the arithmetics with intervals is limited (if not broken) because it simply "increments" the month/year value of the date value. That can lead to invalid dates (e.g. from January to February).
EDIT:
In General Add_months
generally adds 30/31
(depending on months) to the date on which its applied. The case is slight different for monthends. If add_months
is done for month of FEBRUARY
, it will add (28/29) days depending its a leap year
or not.
If your requirement is to simple add 99 years
without checking if the resultant date is a valiad or not, then you can use INTERVAL
, but if you really wanted to check if the resultant date should be very well evaluted and correct date then you must your ADD_MONTHS
. It does not make any sense to first use INTERVAL
then check if the resultant date(using any logic) is a valid date or not. Oracle has already provided solution for such scenarios.
Upvotes: 0
Reputation:
ADD_MONTHS does not add a day to the result. Rather, it has this very general feature: if you ADD MONTHS to a date, and that date is the end of the month in that particular month/year, then the result of ADD_MONTHS is the last day of the resulting month.
So, for example, if you add one month to January 31, you always get February 28 (or Feb 29 in a leap year). If you add one month to June 30, you get July 31.
If you add a month to February 28, you get March 31 UNLESS it's in a leap year; in a leap year Feb 28 is not the last day of the month, so if you add a month to it you get March 28.
In all cases, if the result is a day number greater than the number of days in the resulting month, the result is simply the last day of that month.
EDIT: In a comment below this Answer, the OP asks if there is a way to keep the exact same day of the month, with the exception of Feb. 29 (which should become Feb. 28 in a non-leap year).
The answer is YES. As @Xing shows in the other answer, adding interval '99' year
will preserve the date, but it may cause trouble when the input date is Feb. 29 and the resulting year is not a leap year. That can be fixed with a preliminary check. It can be done with an IF statement or with a CASE expression. I prefer the latter because it works the same in PL/SQL and in SQL; there is no IF in plain SQL.
toretdate := case when to_char(inputdate, 'mm-dd') = '02-29'
then (inputdate + 1) + interval '99' year - 1
else inputdate + interval '99' year end
The trick is, when the inputdate
is 29 February, push it forward one day to make it March 1, then add 99 years (still March 1), and then subtract one day to make it either February 29 (if it's a leap year) or February 28 (otherwise).
Upvotes: 5