Why such inconsistency?
public static void main(String[] args) {
final Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MONTH, 1);
System.out.println("KO current month: " + calendar.get(Calendar.MONTH));
calendar.set(Calendar.MONTH, 1);
System.out.println("OK current month: " + calendar.get(Calendar.MONTH));
}
Output:
KO current month: 2
OK current month: 1
Today is 31st May. The Calendar
object is by default lenient so after the first set()
the date is switched to 31st February which doesn't exist. Calendar
leniently fixes it by moving to 3rd March. Month 2
means March.
The second set()
operation is applied to 3rd March so it switches to 3rd Feb as one would expect. Month 1
means February.
You can see this by formatting the full date:
SimpleDateFormat sdf = new SimpleDateFormat();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MONTH, 1);
System.out.println(sdf.format(calendar.getTime()));
calendar.set(Calendar.MONTH, 1);
System.out.println(sdf.format(calendar.getTime()));
which returns
03/03/18 10:40
03/02/18 10:40
If you want to prevent the behaviour you need to call setLenient()
method
Calendar calendar = Calendar.getInstance();
calendar.setLenient(false);
calendar.set(Calendar.MONTH, 1);
which will results in the following IllegalArgumentException
exception:
Exception in thread "main" java.lang.IllegalArgumentException: MONTH: 1 -> 2 at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:2829) at java.util.Calendar.updateTime(Calendar.java:3393) ...
Karol Dowbecki’s answer is correct and well explained (and I should say well spotted). I should like to provide the good and modern fix.
LocalDate date = LocalDate.of(2018, Month.MAY, 31);
date = date.with(Month.FEBRUARY);
System.out.println(date.getMonth());
System.out.println(date);
Output:
FEBRUARY
2018-02-28
The Calendar
class is confusing and poorly designed, so instead I am using LocalDate
from java.time
, the modern Java date and time API. This API is so much nicer to work with. LocalDate
will not give you February 31, fortunately, since this date does not exist. It gives you the last day of February and thus the month you had expected.
PS The following initialization would mimic your code:
LocalDate date = LocalDate.now(ZoneId.of("Europe/Paris"))`
However, I preferred to give code that will also demonstrate the point when someone tries to run it some day in the future.
Link: Oracle tutorial: Date Time explaining how to use java.time
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With