Reputation: 10947
I am trying to add a year to date but which is giving the same date for different inputs. Input dates are 28/Feb/2020 and 29/Feb/2020 and output are the same for both of them as 28/Feb/2021. Please help me to find what is wrong here.
Update:
I expect as output as 28/Feb/2021 and 01/Mar/2021.
public static Date dateAdd(Date newDate, int field, int amount) {
Calendar aCalendar = Calendar.getInstance();
aCalendar.setTime(newDate);
aCalendar.add(field, amount);
return aCalendar.getTime();
}
public static void main(String[] args) throws Exception {
System.out.println(dateAdd(new SimpleDateFormat("dd/MM/yyyy").parse("28/02/2020"),Calendar.YEAR,1));
System.out.println(dateAdd(new SimpleDateFormat("dd/MM/yyyy").parse("29/02/2020"),Calendar.YEAR,1));
// Console output below
//Sun Feb 28 00:00:00 IST 2021
//Sun Feb 28 00:00:00 IST 2021
}
Upvotes: 1
Views: 866
Reputation: 308
After going through documentation of add and roll. It is clear that what you are looking for is to be found in roll not add.
Further after some research on the topic I found that the given scenario is also to be business dependent and depends what do you want to do because the add and roll gives you the choice to choose either of these.
I found this while searching for the similar problem I had.
Coming back to your code following modification is needed
aCalendar.roll(field, amount);
Someone more expert here will be able to help clean up this answer. JavaDocs for me were not very clear for these so the following question has some interesting answers to it
Upvotes: 5
Reputation: 13261
Nothing is wrong, it depends on the interpretation of "adding one year", for java.util.Calendar#add
, it is:
add(f, delta) adds
delta
to fieldf
. This is equivalent to callingset(f, get(f) + delta)
with two adjustments:Add rule 1. The value of field f after the call minus the value of field f before the call is delta, modulo any overflow that has occurred in field f. Overflow occurs when a field value exceeds its range and, as a result, the next larger field is incremented or decremented and the field value is adjusted back into its range.
Add rule 2. If a smaller field is expected to be invariant, but it is impossible for it to be equal to its prior value because of changes in its minimum or maximum after field f is changed or other constraints, such as time zone offset changes, then its value is adjusted to be as close as possible to its expected value. A smaller field represents a smaller unit of time. HOUR is a smaller field than DAY_OF_MONTH. No adjustment is made to smaller fields that are not expected to be invariant. The calendar system determines what fields are expected to be invariant.
In addition, unlike set(), add() forces an immediate recomputation of the calendar's milliseconds and all fields.
Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling add(Calendar.MONTH, 13) sets the calendar to September 30, 2000. Add rule 1 sets the MONTH field to September, since adding 13 months to August gives September of the next year. Since DAY_OF_MONTH cannot be 31 in September in a GregorianCalendar, add rule 2 sets the DAY_OF_MONTH to 30, the closest possible value. Although it is a smaller field, DAY_OF_WEEK is not adjusted by rule 2, since it is expected to change when the month changes in a GregorianCalendar.
Source: https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html
It sounds consistent with the described behavior, what & why would you expect? Maybe there are better/more specialized solutions.
Upvotes: 2
Reputation: 5034
There is no reason to expect a result of 01/Mar/2021. Indeed, some would then question why adding a year to the two dates 29/Feb/2020 and 01/Mar/2020 would output the same result of 01/Mar/2021 for both of them !
Instead, Java follows a clear, consistent and simple rule : If the result of date arithmetic (such as adding months or years) results in an invalid date, then the answer returned will be the last day of that result’s month.
Eg, from : https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#plusMonths-long-
For example, 2007-03-31 plus one month would result in the invalid date 2007-04-31. Instead of returning an invalid result, the last valid day of the month, 2007-04-30, is selected instead.
Upvotes: 2
Reputation: 139
you can add a year and then add a day:
Date d = dateAdd(new SimpleDateFormat("dd/MM/yyyy").parse("28/02/2020"),Calendar.YEAR,1); // add a year
System.out.println(d);
d = dateAdd(d, Calendar.DATE, 1); // add a day
System.out.println(d);
Upvotes: 0
Reputation: 1237
Use :
System.out.println(dateAdd(new SimpleDateFormat("dd/MM/yyyy").parse("28/02/2020"),Calendar.DAY_OF_YEAR,366));
System.out.println(dateAdd(new SimpleDateFormat("dd/MM/yyyy").parse("29/02/2020"),Calendar.DAY_OF_YEAR,366));
Upvotes: 1