I faced with a strange behavior from java.util.Calendar:
import static org.junit.Assert.*;
import org.junit.Test;
import java.util.Calendar;
public class Tester1 {
@Test
public void test_monthOfDate() {
assertEquals(1, monthOfDate(2013, 1, 30)); // OK
assertEquals(1, monthOfDate(2013, 1, 31)); // OK
// Start of February
assertEquals(2, monthOfDate(2013, 2, 1)); // FAIL
assertEquals(2, monthOfDate(2013, 2, 28)); // FAIL
// to the end of it
// and after that it is okay also
assertEquals(3, monthOfDate(2013, 3, 1)); // OK
}
public int monthOfDate(int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
// just a simple get! but seems it is very important
cal.get(Calendar.MONTH);
//
cal.set(Calendar.DAY_OF_MONTH, day);
return cal.get(Calendar.MONTH) + 1;
}
}
I want to know why exactly this is happening?
Calendar class in Java is an abstract class that provides methods for converting date between a specific instant in time and a set of calendar fields such as MONTH, YEAR, HOUR, etc. It inherits Object class and implements the Comparable, Serializable, Cloneable interfaces.
Not thread safe − java. util. Date is not thread safe, thus developers have to deal with concurrency issue while using date. The new date-time API is immutable and does not have setter methods.
The java.util.calendar class is an abstract class that provides methods for converting between a specific instant in time and a set of calendar fields such as YEAR, MONTH, DAY_OF_MONTH, HOUR, and so on, and for manipulating the calendar fields, such as getting the date of the next week.Following are the important ...
Both Date and Calendar are mutable, which tends to present issues when using either in an API. FYI, the terribly troublesome old date-time classes such as java. util. Date , java.
The problem is that you're starting off with a calendar on January 30th 2013.
You're then setting the year to 2013 - that's not a problem.
You're then setting the month to 1 (i.e. February). What do you expect to happen here? What actually happens is that it will remember that it needs to set the month to 1, but not recompute the actual time value. The time value will be recomputed on your call to get
though, as per the documentation (emphsis mine):
set(f, value) changes calendar field f to value. In addition, it sets an internal member variable to indicate that calendar field f has been changed. Although calendar field f is changed immediately, the calendar's time value in milliseconds is not recomputed until the next call to get(), getTime(), getTimeInMillis(), add(), or roll() is made. Thus, multiple calls to set() do not trigger multiple, unnecessary computations. As a result of changing a calendar field using set(), other calendar fields may also change, depending on the calendar field, the calendar field value, and the calendar system. In addition, get(f) will not necessarily return value set by the call to the set method after the calendar fields have been recomputed. The specifics are determined by the concrete calendar class.
When you try to change "January 30th" to "February 30th" and force a computation, what actually happens is that you end up on March 2nd on my box - but it may differ on your implementation.
The best fixes are:
Calendar.set(year, month, date)
instead to avoid this ordering issueIf 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