I'm trying to get the sunday of the same week as a given date. During this I ran into this problem:
Calendar calendar = Calendar.getInstance(Locale.GERMANY);
calendar.set(2017, 11, 11);
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(calendar.getTime().toString());
results in "Sun Jan 07 11:18:42 CET 2018"
but
Calendar calendar2 = Calendar.getInstance(Locale.GERMANY);
calendar2.set(2017, 11, 11);
calendar2.getTime();
calendar2.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(calendar2.getTime().toString());
gives me the correct Date "Sun Dec 17 11:18:42 CET 2017"
Can someone explain why the first exmple is behaving this way? Is this really intended?
Thanks
As Jon Skeet said, avoid
Calendar
. For your case it is truly horrible, and it’s poorly designed in general. Instead doThis prints the expected date
As others have already mentioned, the solution is to use
java.time
, the modern Java date and time API. Also generally it is so much nicer to work with. One nice feature is theLocalDate
class that I am using. It is a date without time of day, which seems to match your requirements more precisely thatCalendar
did.If the above looks complicated, it’s because, as I think you are aware, “Sunday of the same week” means different things in different locales. In the international standard that Germany follows, weeks begin on Monday, so Sunday is the last day of the week. In the American standard, for example, Sunday os the first day of the week.
WeekFields.dayOfWeek()
numbers the days of the week from 1 to 7, so when we want to set the day to Sunday, we first need to find out which number Sunday has got in this numbering (7 in Germany, 1 in the US). So for any Sunday, get itsweekFieldsForLocale.dayOfWeek()
value and later use this for setting the day of week to Sunday. The reason why this is necessary is that thewith()
method is so general and therefore has been designed to accept only numeric values; we can’t just pass it aDayOfWeek
object.If I substitute
Locale.US
into the code, I get2017-12-10
, which is the correct Sunday for a calendar where Sunday is the first day of the week. If you are sure your only want your code to work for Germany, you may of course just hardcode a7
(please make it a constant with a very explanatory name).Link: Oracle Tutorial Date Time explaining how to use
java.time
. There are other resources on the net (just avoid the outdated placed that suggestjava.util.Calendar
:-)Basically, the
Calendar
API is horrible, and should be avoided. It's not documented terribly clearly, but I think I see where it's going, and it's behaving as intended in this situation. By that I mean it's following the intention of the API authors, not the intention of you or anyone reading your code...From the documentation:
And then:
In the first example, the fact that the last field set was "day of week" means it will then use the
YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
calculation (I think). The year and month have been set to December 2017, but the week-of-month is the current week-of-month, which is the week 5 of January 2018... so when you then say to set the day of week to Sunday, it's finding the Sunday in the "week 5" of December 2017. December only had 4 weeks, so it's effectively rolling it forward... I think. It's all messy and you shouldn't have to think about that, basically.In the second example, calling
getTime()
"locks in" the year/month/day you've specified, and computes the other fields. When you set the day of week, that's then adjusting it within the existing computed fields.Basically, avoid this API as far as you possibly can. Use
java.time
, which is a far cleaner date/time API.