Can someone please explain why is the behavior of the below piece of code not as expected.
import java.util.Calendar;
import java.util.Date;
import java.text.SimpleDateFormat;
public class Test {
public static void main(String[] args) {
int numberOfYears = 3;
Calendar now = Calendar.getInstance();//Today's date is December 28, 2023
now.add(Calendar.YEAR, numberOfYears);// Adding 3 years to it
Date date = now.getTime();
String expectedExpiryDate = new SimpleDateFormat("MMMM d, YYYY").format(date); //expected date should be December 28, 2026
System.out.println(expectedExpiryDate + " expectedExpiryDate");// But we are getting output as December 28, 2027
}
}
If we add 1 year to today's date then we do get expected result i.e December 28, 2024. However, if we add 2 or 3 years to today's date it becomes December 28, 2026 and December 28, 2027 respectively
tl;dr
Avoid legacy date-time classes
Stop using
Calendar. That class is a legacy class, long ago supplanted by the modern java.time classes defined in JSR 310. Never useCalendar,SimpleDateFormat,Date,Date,Timestamp, etc.Do not waste your time trying to understand these legacy date-time classes. They are terribly flawed, with bizarre features. They are entirely replaced by java.time, so move on. Sun, Oracle, and the JCP community have.
java.time
Capture the current date only, without time-of-day, and without time zone, use
java.time.LocalDate.Determining the current date requires a time zone. If omitted the JVM’s current default time zone is implicitly applied.
Add three years.
To generate text is standard ISO 8601 format, call
toString. To generate text in localized format, useDateTimeFormatter.ofLocalizedDate.Be sure to specify your desired/expected locale. Relying on the JVM’s current default locale can be dicey. And doing so implicitly (by omitting any mention of locale) leaves the user wondering if you are aware of how localization works.