Java 8 LocalDate: определите, какой понедельник месяца (1, 2, 3 и т. Д.)

Я пытаюсь выяснить, как определить, является ли определенный понедельник первым, вторым, третьим или четвертым понедельником данного месяца. Я выяснил, как получить следующий понедельник и неделю месяца, которые находятся в использовании класса LocalDate.

LocalDate now = LocalDate.of(2018, 2, 1);
LocalDate nextMonday = now.with(next(DayOfWeek.MONDAY));
WeekFields weekFields = WeekFields.of(Locale.getDefault());
int week = nextMonday.get(weekFields.weekOfMonth());

В приведенном выше примере код получает следующий понедельник и неделю, в которой он находится. Неделя - вторая неделя февраля, но этот понедельник - не второй, а первый. Любая помощь с этим будет принята с благодарностью.

4 ответа

Решение

Изменить: Вы должны принять ответ Оле В. V (ChronoField.ALIGNED_WEEK_OF_MONTH) вместо этого ответа.

Вы можете выяснить, какой это день месяца, разделить на 7 и добавить 1:

LocalDate nextMonday = now.with(next(DayOfWeek.MONDAY));
int weekNo = ((nextMonday.getDayOfMonth()-1) / 7) +1;

Например, этот код:

LocalDate now = LocalDate.of(2018, 2, 1);
for(int i = 0; i < 10; i++) {
    now = now.with(next(DayOfWeek.MONDAY));
    int weekNo = ((now.getDayOfMonth()-1) / 7) +1;
    System.out.println("Date : " + now + " == " + weekNo);
}

Распечатывает следующее, что, как я полагаю, вы хотите...

Date : 2018-02-05 == 1
Date : 2018-02-12 == 2
Date : 2018-02-19 == 3
Date : 2018-02-26 == 4
Date : 2018-03-05 == 1
Date : 2018-03-12 == 2
Date : 2018-03-19 == 3
Date : 2018-03-26 == 4
Date : 2018-04-02 == 1
Date : 2018-04-09 == 2

Вы не должны использовать свою собственную арифметику для этого. Используйте встроенный функционал:

    int week = nextMonday.get(ChronoField.ALIGNED_WEEK_OF_MONTH);

С датой из вашего кода это дает:

1

Это означает, что понедельник, который вы получили (5 февраля), является первым понедельником месяца. Также вам не нужно никаких WeekFields потому что первый понедельник месяца - это первый понедельник месяца, независимо от того, какой день является первым днем ​​недели или как нумеруются недели года.

Арифметика дат часто сложна и ее легко ошибиться. Это также означает, что даже если вы, наконец, правильно выполнили свои вычисления, читателю трудно убедить себя в том, что ваш код верен. Поэтому всегда лучше использовать встроенную функциональность, которая, как мы надеемся, будет протестирована и которая использует пояснительные имена, а не цифры, такие как 1 и 7.

Вы можете быть удивлены, что поле для использования называется ALIGNED_WEEK_OF_MONTH, Думайте о выровненных неделях как о неделях, начинающихся 1-го числа месяца, независимо от дня недели, и следующих недель, следующих друг за другом. В феврале 2018 года первая выровненная неделя начинается с четверга, 1 февраля, до среды, 7 февраля. Следующие выровненные недели начинаются по четвергам 8, 15 и 22 февраля. Очевидно, что первый понедельник месяца приходится на первую неделю, 2-й понедельник на 2-й неделе и т. Д. Поэтому он работает, чтобы использовать ALIGNED_WEEK_OF_MONTH,

Вы можете попытаться многократно вычитать неделю от даты до изменения месяца. Тогда количество раз, которое вы сделали, будет исходной датой "X-й день недели в месяце".

РЕДАКТИРОВАТЬ: некоторый код.

LocalDate now = LocalDate.of(2018, 2, 1);

int i = 0;
Month originalMonth = now.getMonth();
while (now.getMonth() == originalMonth) { // its an enum, you can do this
    now = now.plusWeeks(-1);
    i++;
}

System.out.println(i); // prints 1
String[] arr = { "2018-01-01", "2018-01-07", "2018-01-30", "2018-01-22", 
               "2018-01-25" };
for (String str : arr) {
    LocalDate ld = LocalDate.parse(str);
    ld = ld.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
    int res = (ld.getDayOfMonth()/7) + 
                   (Integer.min(1, ld.getDayOfMonth() % 7));
    System.out.printf("%s  => %d\n", str, res);
}
Другие вопросы по тегам