如何使用LocalDate-Java获得一个月的工作日数量

Tec*_*mer -3 java calendar weekday localdate

如何在一个月内获得工作日(周一至周五)的数量LocalDate?我以前从未使用java.time过,所以我不知道它的所有工作原理.我一直在寻找这个网站,无法找到答案.我也不想使用任何外部库.

例如:截至本月,2018年4月,有21个工作日.下个月有23个工作日.

And*_*eas 5

如果需要,请参见最后的优化蛮力解决方案

这是一个非暴力实施计算一个月的工作日(周一至周五).

它使用YearMonth而不是LocalDate,因为日期值对计算没有意义.

public static int weekDaysInMonth(YearMonth yearMonth) {
    int len = yearMonth.lengthOfMonth(); // 28-31, supporting leap year
    int dow = yearMonth.atDay(1).getDayOfWeek().getValue(); // 1=Mon, 7=Sun
    return (dow <= 5 ? Math.min(len - 8, 26 - dow) : Math.max(len + dow - 16, 20));
}
Run Code Online (Sandbox Code Playgroud)

这是一个超载LocalDate,如果这就是你所拥有的那么很容易打电话.

public static int weekDaysInMonth(LocalDate date) {
    return weekDaysInMonth(YearMonth.from(date));
}
Run Code Online (Sandbox Code Playgroud)

测试

System.out.println(weekDaysInMonth(LocalDate.parse("2018-04-15"))); // April 15, 2018
System.out.println(weekDaysInMonth(YearMonth.of(2018, 5)));         // May 2018
Run Code Online (Sandbox Code Playgroud)

产量

21
23
Run Code Online (Sandbox Code Playgroud)

公式的解释

return声明中的公式是通过检查每个组合len(月中的天数,28-31)和dow(月的第一天的星期几,1 =星期一 - 7 =太阳)的预期返回值创建的:

   |  1   2   3   4   5    6   7
   | Mo  Tu  We  Th  Fr   Sa  Su
---+----------------------------
28 | 20  20  20  20  20   20  20
29 | 21  21  21  21  21   20  20
30 | 22  22  22  22  21   20  21
31 | 23  23  23  22  21   21  22
Run Code Online (Sandbox Code Playgroud)

解释dow <= 5(周一至周五)

最初是len - 8工作日,即我们减去一个月内总是存在的4个周末.

当我们到达星期四和星期五时,我们需要限制我们失去的1或2个周末日.如果你查看31天的行,我们将其上限26 - dow,即周五(dow=5)我们上限21,周四(dow=4)我们上限22.对于周一至周三,我们也有上限,但上限等于或高于初始计算,因此无关紧要.

使用min(xxx, cap)方法完成封顶,因此我们得到:

min(len - 8, 26 - dow)
Run Code Online (Sandbox Code Playgroud)

dow >= 6(星期六)的解释

你可以在右下角看到一个小三角形.如果我们扩展该模式,我们得到:

   |  4   5   6   7
---+---------------
28 | 16  17  18  19
29 | 17  18  19  20
30 | 18  19  20  21
31 | 19  20  21  22
Run Code Online (Sandbox Code Playgroud)

作为一个公式,即len + dow - 16.

将其与原始网格进行比较,数字最低限度20,这是使用max(xxx, bottom)方法完成的,因此我们得到:

max(len + dow - 16, 20)
Run Code Online (Sandbox Code Playgroud)

结论

最后,我们使用三元条件运算符将两者结合起来:

dow <= 5  ?  min(len - 8, 26 - dow)  :  max(len + dow - 16, 20)
Run Code Online (Sandbox Code Playgroud)

那么完整的Java语句是:

return (dow <= 5 ? Math.min(len - 8, 26 - dow) : Math.max(len + dow - 16, 20));
Run Code Online (Sandbox Code Playgroud)

蛮力解决方案

如果您更喜欢蛮力解决方案,可以通过跳过一个月内始终存在的前4周来缓解它:

public static int weekDaysInMonth(LocalDate refDate) {
    LocalDate firstOfMonth = refDate.withDayOfMonth(1);
    LocalDate nextMonth = firstOfMonth.plusMonths(1);
    int days = 20;
    for (LocalDate date = firstOfMonth.plusDays(28); date.isBefore(nextMonth); date = date.plusDays(1))
        if (date.getDayOfWeek().getValue() <= 5) // 1=Mon - 5=Fri, i.e. not 6=Sat and 7=Sun
            days++;
    return days;
}
Run Code Online (Sandbox Code Playgroud)