3

I am looking to build up a function that return an array with all week numbers of the previous months in a year that are the same week number of one particular month.

I am using as first day of week Monday and I am taking as first week of month week with the first Monday of current month.

Input: week of year and year. For example, 27 and 2019. The first week of July (7).

Output: array of week of months. For example, [2, 6, 10, 14, 19, 23, 27].

What I try:

private void getResult(int weekYear)
{
    LocalDate date = LocalDate.now();
    final int weekNumber = 27;
    LocalDate newDate = date.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber);
    int month = newDate.getMonthValue();;
        
    int weekMonth = LocalDate.from(newDate).get(WeekFields.ISO.weekOfMonth());
        
    System.out.println(newDate);
    System.out.println(month);
    System.out.println(weekMonth);
        
    ArrayList<Integer> list = new ArrayList<Integer>();
        
    for (int i = 1; i <= month; i++)
    {
        LocalDate tempDate = date.withYear(2019).withMonth(i).with(WeekFields.ISO.weekOfMonth(), weekMonth);
        int tempYear = LocalDate.from(tempDate).get(WeekFields.ISO.weekOfWeekBasedYear());
        list.add(tempYear);
    }
        
    list.forEach((e) -> System.out.print(e + " "));
}
int weekYear = 27;
getResult(weekYear);

What I get: [1 6 10 14 18 23 27].

What I am looking for: I have two question:

  1. First one: the results obtained are different from those expected. I think the problem is due to the fact that I didn't specify how to calculate the first week of the month (first Monday of the month). Is it right? How can I solve that?
  2. Second one: What is a better solution?
Nimantha
  • 6,405
  • 6
  • 28
  • 69
lezan
  • 759
  • 6
  • 23
  • I think you should split your questions. Question #1 is on topic for StackOverflow. Question #2 would be better at https://codereview.stackexchange.com/ *after* you have a working implementation. – Freiheit Aug 19 '19 at 20:04
  • @Freiheit thanks for your interest. I will follow your suggestion. – lezan Aug 19 '19 at 20:16
  • I think this function can solve the problem: firstIntMonth https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html#firstInMonth-java.time.DayOfWeek-. Switching to ```LocalDate tempDate = date.withYear(2019).withMonth(i).with(WeekFields.ISO.weekOfMonth(), weekMonth).with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));``` return the right list. – lezan Aug 19 '19 at 20:20
  • @lezan No. First, I get `2 6 10 14 14 23 27 `, notice that 14 comes twice. Second, if your starting point happens to be in, say, the second or the fourth week of the month, `firstInMonth` obviously won’t give you that. – Ole V.V. Aug 20 '19 at 08:57

1 Answers1

2

The key here is understanding a few points:

  1. You are numbering weeks in two different ways. For the week of year you are using ISO numbering: the first week of the year is the one that includes at least 4 days of the new year. For week of month you are counting the Mondays (you may say that the first week of the month is the one that includes seven days of the month, not four).
  2. The week number may not always exist. If your starting point is in 0th or the 5th week of the month, a preceding month may not have that week in it.

the results obtained are different from those expected. I think the problem is due to the fact that I didn't specify how to calculate the first week of the month (first Monday of the month). Is it right? How can I solve that?

You are correct. To count the Mondays of the month you may use:

        LocalDate tempDate = date.withYear(2019)
                .withMonth(i)
                .with(ChronoField.DAY_OF_WEEK, DayOfWeek.MONDAY.getValue())
                .with(ChronoField.ALIGNED_WEEK_OF_MONTH, weekMonth);

(DayOfWeek.MONDAY.getValue() is just of wordy way of saying 1, of course, but conveys the intention better, so I prefer it.)

With this change to your code the output is the expected:

2 6 10 14 19 23 27

The key is ChronoField.ALIGNED_WEEK_OF_MONTH. The aligned weeks of a month start from the 1st of the month and are always 7 days regardless of the days of the week. The first aligned week is from the 1st through the 7th of the month, the 2nd aligned week if from 8th through 14th, etc. Since we have set the day of week to Monday, setting the aligned week to 1 gives us the 1st Monday of the month, etc.

We’re not done yet. If I set weekNumber to 40, I get:

2 6 10 14 14 23 27 27 36 41

I had expected 40 to be the last number in the list, but it is not there. Week 40 of 2019 is from Monday September 30 through October 6, so if I understand correctly you want the 5th week of those months that have a 5th week. This brings us back to the issue of not all month having a week 5 (because they don’t have 5 Mondays). What happened was that since I ran your code on a Tuesday, it took Tuesday in week 40, which is October 1, as a starting point, and therefore gave me the 1st rather than the 5th week of every month.

are there better solutions? Can you suggest one?

I can’t really. What you’ve got is fine.

Only you’re not using the int weekYear parameter. You may want to use it in place of your weekNumber local variable. In any case you should delete one of them and use the other.

And this unrelated tip: Your use of LocalDate.from(someLocalDate) is redundant since it just gives you the same LocalDate again (either the same object or an equal one, I don’t know or care). Just use someLocalDate in those situations.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Thanks for your answer. I am taking some time to get what did you write and I will come with a feedback soon. – lezan Aug 20 '19 at 09:49
  • I made several mistakes: first of all I had not taken into consideration what you said in point 1). I cannot use as first week of month the first Monday of month. I think using two different rappresentation (iso and not-iso) for week of year and week of month is not good, do too much confusion. Said this [1 6 10 14 18 23 27] is the first week of month with iso rappresentation, right? – lezan Aug 20 '19 at 10:13
  • Second mistake, when you said "Only you’re not using the.." you are right: I made an error reporting on stackoverflow a simplified version of my code. I am doing the right tihing here. Third mistake, when you said "And this unrelated tip..": so can I use ```int weekMonth = newDate.get(WeekFields.ISO.weekOfMonth());``` and ```int tempYear = tempDate,get(WeekFields.ISO.weekOfWeekBasedYear());```, right? – lezan Aug 20 '19 at 10:21
  • 1
    Yes, I agree that the first ISO week of the each month would be 1 6 10 14 18 23 27. And yes, `int weekMonth = newDate.get(WeekFields.ISO.weekOfMonth());` and `int tempYear = tempDate.get(WeekFields.ISO.weekOfWeekBasedYear());` will give the same result as the code you had in those places. @lezan – Ole V.V. Aug 20 '19 at 17:22
  • So if w6-2019 is the first week of February, what about w5-2019? Is the last week of January? Is January going to be a a month with 5 weeks? – lezan Aug 21 '19 at 09:00
  • Interesting question, @lezan. Week 6 (Feb 4 through 10) is the first week of February no matter if you require four or seven days of the week to be within the month. The count of months in January depends on your definition, though. There are only 4 Mondays in January. Monday of week 1 falls on December 31 the previous year. – Ole V.V. Aug 21 '19 at 11:16