I am facing a weird behavior of java.util.Calendar
.
The problem is when I add a method call Calendar#getTime()
in between only than I get correct result but when I directly get the Dates
of the week without calling Calendar#getTime()
it refers to the next week instead of current week.
Please consider following code snippet :
public class GetDatesOfWeek {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
Calendar cal = Calendar.getInstance();
cal.set(1991, Calendar.DECEMBER, 11);
//System.out.println(cal.getTime());//LINE NO : 14
for(int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
cal.set(Calendar.DAY_OF_WEEK, i);
Date date = cal.getTime();
System.out.println(sdf.format(date));
}
}
}
When I uncomment the line no 14
I get following output :
Wed Dec 11 07:38:06 IST 1991
08-12-1991
09-12-1991
10-12-1991
11-12-1991
12-12-1991
13-12-1991
14-12-1991
But when I comment that line and execute the code I get following output.
15-12-1991
16-12-1991
17-12-1991
18-12-1991
19-12-1991
20-12-1991
21-12-1991
Note that in both the cases month and year fields are proper but the start date changed from 08-12-1991
to 15-12-1991
for me 08-12-1991
is correct.
My Question :
If you step through your code in a debugger, you will see interesting things happen to the internal variables of the cal
object.
The calendar object stores both the time it represents and adjustment fields separately. After executing line 12, the cal object is constructed with the current time and no adjustment fields, and its internal variable isTimeSet
is set to true. This means that the internal time stored is correct.
Executing line 13 clears isTimeSet
to false because now the internal time needs to be adjusted by the adjustment fields before it is accurate again. This doesn't happen immediately, rather it waits for a call to getTime()
or get(...)
, getTimeInMillis()
, add(...)
or roll(...)
.
Line 14 (if uncommented) forces the internal time to be recalculated using the adjustment fields, and sets the isTimeSet
variable to true again.
Line 17 then sets another adjustment field, and unsets the isTimeSet
variable again.
Line 18 recalculates the correct time again, based on the adjustment field set in line 17.
The solution:
The problem occurs when you combine setting the day-of-month with the day-of-week. When the day-of-week is set, the day-of-month setting is ignored, and the current day-of-month in the cal
object is used as a starting point. You happen to be getting a week starting on the 15th because today's date is the 12th and 15th Dec 1991 is the nearest Sunday to 12th Dec 1991.
Note: If you run your test again in a week's time, you will get a different result.
The solution is to call getTimeInMillis()
or getTime()
to force recalculation of the time before setting day-of-week adjustments.
Testing:
If you don't want to wait a week to test again, try the following:
public class GetDatesOfWeek {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
Calendar cal = Calendar.getInstance();
cal.set(2015, Calendar.AUGUST, 1); // adjust this date and see what happens
cal.getTime();
cal.set(1991, Calendar.DECEMBER, 11);
//System.out.println(cal.getTime());//LINE NO : 14
for(int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
cal.set(Calendar.DAY_OF_WEEK, i);
Date date = cal.getTime();
System.out.println(sdf.format(date));
}
}
}
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