I need to get week span: start of week (Mo) | end of week (Sun) in days of year.
For example, for 5.9.2019, it should be 241-247 (days starting from 0).
However, my method produces 250 | 249
public static Pair<Integer, Integer> getWeekSpan(Timestamp date) {
Pair<Integer, Integer> result = new Pair<Integer, Integer>();
Calendar cal = timestampToCalendar(date);
// start of week
cal.set(Calendar.DAY_OF_WEEK, cal.getActualMinimum(Calendar.DAY_OF_WEEK));
result.setKey(cal.get(Calendar.DAY_OF_YEAR) - 1);
// end of week
cal.set(Calendar.DAY_OF_WEEK, cal.getActualMaximum(Calendar.DAY_OF_WEEK));
result.setValue(cal.get(Calendar.DAY_OF_YEAR) - 1);
return result;
}
public static Calendar timestampToCalendar(Timestamp timestamp) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timestamp.getTime());
return cal;
}
public static Pair<Integer, Integer> getWeekSpan(LocalDate date) {
return new Pair<>(getZeroBasedDayOfYear(date.with(DayOfWeek.MONDAY)),
getZeroBasedDayOfYear(date.with(DayOfWeek.SUNDAY)));
}
private static int getZeroBasedDayOfYear(LocalDate date) {
return date.getDayOfYear() - 1;
}
Output:
[244, 250]
It doesn’t agree exactly with what you said you expected, but it does agree with what I get from running the code in your own answer, so I trust that it is correct. The numbers correspond to Monday, September 2 and Sunday, September 8, 2019.
I don’t know whether your Pair
class has got a 2-argument constructor. If not, I trust you to fill in the two integers in the same way you did in the question.
Beware that a week may cross New Year. If for instance I specify 2019-12-31, I get:
[363, 4]
4 refers to January 5 of the following year.
My code relies on the fact that you want ISO weeks, where Monday is the first day of the week. If required, we can introduce more flexibility through a WeekFields
object:
public static Pair<Integer, Integer> getWeekSpan(LocalDate date) {
WeekFields wf = WeekFields.ISO;
return new Pair<>(getZeroBasedDayOfYear(date.with(wf.dayOfWeek(), 1)),
getZeroBasedDayOfYear(date.with(wf.dayOfWeek(), 7)));
}
As long as I use WeekFields.ISO
, the result is still the same, but this is where you might plug in, for example WeekFields.of(Locale.getDefault())
if you wanted to use the week definition of the default locale.
The classes you were using, Timestamp
and Calendar
, are poorly designed and long outdated. I recommend you don’t use them. Instead I am using LocalDate
from java.time, the modern Java date and time API.
If you’ve got a Timestamp
object from a legacy API that you cannot change or don’t want to upgrade just now, the way to convert to a LocalDate
is:
LocalDate convertedLocalDate = yourTimestamp.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
This is one of the places where the Calendar
class is getting confusing. It numbers the days of the week from 1 for Sunday through 7 for Saturday. So when you ask for the actual minimum and maximum, you get 1 for Sunday and 7 for Saturday even though these are not the first and the last day of the week. So what happened was that you first set the day of week to Sunday, yielding September 8 because your week starts on Monday. BTW, Calendar.getInstance()
picks up the week definition from your default locale, which cannot be read from the code and is likely to confuse many too. And even more so if one day your code runs on a JVM with a different default locale and suddenly behaves differently. Next when setting the day of the week to max, 7, you got Saturday, September 7. The dates were translated correctly to 250 and 249.
Oracle tutorial: Date Time explaining how to use java.time.