如果需要,请参见最后的优化蛮力解决方案
这是一个非暴力实施计算一个月的工作日(周一至周五).
它使用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)
| 归档时间: |
|
| 查看次数: |
94 次 |
| 最近记录: |