我如何使用 LocalDate 获得一个月中的工作日数量 - Java
How would I get the amount of weekdays in a month with LocalDate - Java
我如何使用 LocalDate
获取一个月中的工作日(周一至周五)天数?我以前从未使用过 java.time
所以我不知道它的所有工作原理。我一直在这个网站上寻找答案,但无济于事。我也不想使用任何外部库。
示例:截至本月,即 2018 年 4 月,有 21 个工作日。下个月有23个工作日。
所以,感谢 Dreamspace 总裁帮我找到了解决方案(尽管这是一种蛮力方式),他说的是:
Create a LocalDate for the first day of the respective month. Loop until the end of the month using ld.plusDays(1) and use ld.getDayOfWeek() to see which DayOfWeek you're dealing with.
这是我发现的工作方式:
public static int businessDaysInMonth(final LocalDate ld) {
int weekDays = 0;
LocalDate date = ld.withDayOfMonth(1);
final int intendedMonthValue = ld.getMonthValue();
do {
final DayOfWeek dayOfWeek = date.getDayOfWeek();
if (dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY) {
weekDays++;
}
date = date.plusDays(1);
} while (date.getMonthValue() == intendedMonthValue);
return weekDays;
}
如果需要,请参阅最后的优化暴力解决方案
这是一个非蛮力实现,用于计算 一个月中的工作日(周一至周五)。
它使用 YearMonth
instead of 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));
}
这是一个采用 LocalDate
的重载,所以如果你有的话,很容易调用。
public static int weekDaysInMonth(LocalDate date) {
return weekDaysInMonth(YearMonth.from(date));
}
测试
System.out.println(weekDaysInMonth(LocalDate.parse("2018-04-15"))); // April 15, 2018
System.out.println(weekDaysInMonth(YearMonth.of(2018, 5))); // May 2018
输出
21
23
公式解释
return
语句中的公式是通过检查 len
(月中的天数,28 - 31)和 [= 的每个组合的预期 return 值创建的26=](每月第一天的星期几,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
dow <= 5
(周一至周五)的解释
最初有 len - 8
个工作日,即我们减去一个月中始终存在的 4 个周末。
到了周四和周五,我们需要限制我们失去的 1 或 2 个周末。如果您查看 31 天的行,我们将其上限设为 26 - dow
,即周五 (dow=5
) 我们将上限设为 21
,而周四 (dow=4
) 我们上限为 22
。周一到周三,我们也有上限,但上限等于或高于初始计算,所以没关系。
封顶是使用min(xxx, cap)
方法完成的,所以我们得到:
min(len - 8, 26 - dow)
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
作为一个公式,即len + dow - 16
.
与原始网格相比,数字在 20
处触底,这是使用 max(xxx, bottom)
方法完成的,所以我们得到:
max(len + dow - 16, 20)
结论
最后我们使用三元条件运算符将两者结合起来:
dow <= 5 ? min(len - 8, 26 - dow) : max(len + dow - 16, 20)
完整的 Java 语句是:
return (dow <= 5 ? Math.min(len - 8, 26 - dow) : Math.max(len + dow - 16, 20));
暴力破解
如果您更喜欢强力解决方案,您可以通过跳过一个月中始终存在的前 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;
}
我如何使用 LocalDate
获取一个月中的工作日(周一至周五)天数?我以前从未使用过 java.time
所以我不知道它的所有工作原理。我一直在这个网站上寻找答案,但无济于事。我也不想使用任何外部库。
示例:截至本月,即 2018 年 4 月,有 21 个工作日。下个月有23个工作日。
所以,感谢 Dreamspace 总裁帮我找到了解决方案(尽管这是一种蛮力方式),他说的是:
Create a LocalDate for the first day of the respective month. Loop until the end of the month using ld.plusDays(1) and use ld.getDayOfWeek() to see which DayOfWeek you're dealing with.
这是我发现的工作方式:
public static int businessDaysInMonth(final LocalDate ld) {
int weekDays = 0;
LocalDate date = ld.withDayOfMonth(1);
final int intendedMonthValue = ld.getMonthValue();
do {
final DayOfWeek dayOfWeek = date.getDayOfWeek();
if (dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY) {
weekDays++;
}
date = date.plusDays(1);
} while (date.getMonthValue() == intendedMonthValue);
return weekDays;
}
如果需要,请参阅最后的优化暴力解决方案
这是一个非蛮力实现,用于计算 一个月中的工作日(周一至周五)。
它使用 YearMonth
instead of 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));
}
这是一个采用 LocalDate
的重载,所以如果你有的话,很容易调用。
public static int weekDaysInMonth(LocalDate date) {
return weekDaysInMonth(YearMonth.from(date));
}
测试
System.out.println(weekDaysInMonth(LocalDate.parse("2018-04-15"))); // April 15, 2018
System.out.println(weekDaysInMonth(YearMonth.of(2018, 5))); // May 2018
输出
21
23
公式解释
return
语句中的公式是通过检查 len
(月中的天数,28 - 31)和 [= 的每个组合的预期 return 值创建的26=](每月第一天的星期几,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
dow <= 5
(周一至周五)的解释
最初有 len - 8
个工作日,即我们减去一个月中始终存在的 4 个周末。
到了周四和周五,我们需要限制我们失去的 1 或 2 个周末。如果您查看 31 天的行,我们将其上限设为 26 - dow
,即周五 (dow=5
) 我们将上限设为 21
,而周四 (dow=4
) 我们上限为 22
。周一到周三,我们也有上限,但上限等于或高于初始计算,所以没关系。
封顶是使用min(xxx, cap)
方法完成的,所以我们得到:
min(len - 8, 26 - dow)
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
作为一个公式,即len + dow - 16
.
与原始网格相比,数字在 20
处触底,这是使用 max(xxx, bottom)
方法完成的,所以我们得到:
max(len + dow - 16, 20)
结论
最后我们使用三元条件运算符将两者结合起来:
dow <= 5 ? min(len - 8, 26 - dow) : max(len + dow - 16, 20)
完整的 Java 语句是:
return (dow <= 5 ? Math.min(len - 8, 26 - dow) : Math.max(len + dow - 16, 20));
暴力破解
如果您更喜欢强力解决方案,您可以通过跳过一个月中始终存在的前 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;
}