Java 计算工作日,休假,调休,调班等
/*** 用于判断n个工作日(排除节假日、周六日包含节后补班数据)后的日期* @param list 节假日数据源* @param weekDayList 节后补班数据源* @param today计算开始时间* @param num多少个工作日 根据需要自行安排* @throws ParseException*/public static Date getScheduleActiveDate(.
·
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class WorkdayCalculator {
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 使用Set提高查询效率
private final Set<LocalDate> holidays;
private final Set<LocalDate> workWeekends;
// 缓存已计算的日期结果
private final Map<LocalDate, Boolean> workdayCache = new ConcurrentHashMap<>();
public WorkdayCalculator(List<String> holidayList, List<String> workWeekendList) {
this.holidays = parseDateStrings(holidayList);
this.workWeekends = parseDateStrings(workWeekendList);
}
private Set<LocalDate> parseDateStrings(List<String> dateStrings) {
return dateStrings.stream()
.map(str -> LocalDate.parse(str, DATE_FORMAT))
.collect(Collectors.toSet());
}
/**
* 计算n个工作日后的日期
* @param startDate 开始日期
* @param workdays 工作日数量
* @return 目标日期
*/
public LocalDate calculateWorkdayAfter(LocalDate startDate, int workdays) {
LocalDate current = startDate;
int remaining = workdays;
while (remaining > 0) {
current = current.plusDays(1);
if (isWorkday(current)) {
remaining--;
}
}
return current;
}
/**
* 计算两个日期之间的工作日和节假日天数
* @param start 开始日期
* @param end 结束日期
* @return 包含工作日和节假日天数的Map
*/
public Map<String, Long> countWorkdaysAndHolidays(LocalDate start, LocalDate end) {
long workdays = 0;
long holidays = 0;
LocalDate current = start;
while (!current.isAfter(end)) {
if (isWorkday(current)) {
workdays++;
} else {
holidays++;
}
current = current.plusDays(1);
}
return Map.of(
"workdays", workdays,
"holidays", holidays
);
}
/**
* 判断是否是工作日
*/
public boolean isWorkday(LocalDate date) {
return workdayCache.computeIfAbsent(date, d -> {
// 优先检查是否是调休的工作日
if (workWeekends.contains(d)) {
return true;
}
// 检查是否是节假日
if (holidays.contains(d)) {
return false;
}
// 检查是否是周末
DayOfWeek dayOfWeek = d.getDayOfWeek();
return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
});
}
/**
* 计算两个日期时间之间的时间差
*/
public String formatDurationBetween(LocalDateTime start, LocalDateTime end) {
Duration duration = Duration.between(start, end);
long hours = duration.toHours();
long minutes = duration.minusHours(hours).toMinutes();
return String.format("%d小时%d分钟", hours, minutes);
}
// 转换方法保持兼容性
public static LocalDate toLocalDate(Date date) {
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
}
public static LocalDateTime toLocalDateTime(Date date) {
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}
public static Date toDate(LocalDate localDate) {
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
}
}
这个WorkdayCalculator类是一个工作日计算工具,用于处理与工作日相关的各种计算,包括判断某天是否是工作日、计算工作日后的日期、统计两个日期之间的工作日和节假日天数等。
主要功能方法
calculateWorkdayAfter - 计算n个工作日后的日期
public LocalDate calculateWorkdayAfter(LocalDate startDate, int workdays) {
LocalDate current = startDate;
int remaining = workdays;
while (remaining > 0) {
current = current.plusDays(1);
if (isWorkday(current)) {
remaining--;
}
}
return current;
}
这个方法:
- 从开始日期开始,逐天向后检查
- 遇到工作日时减少剩余工作日计数
- 直到剩余工作日为0时返回当前日期
countWorkdaysAndHolidays - 统计两个日期间的工作日和节假日天数
public Map<String, Long> countWorkdaysAndHolidays(LocalDate start, LocalDate end) {
long workdays = 0;
long holidays = 0;
LocalDate current = start;
while (!current.isAfter(end)) {
if (isWorkday(current)) {
workdays++;
} else {
holidays++;
}
current = current.plusDays(1);
}
return Map.of(
"workdays", workdays,
"holidays", holidays
);
}
这个方法:
- 初始化工作日和节假日计数器
- 从开始日期到结束日期逐天检查
- 使用
isWorkday方法判断是否是工作日 - 返回包含统计结果的Map
isWorkday - 判断是否是工作日
public boolean isWorkday(LocalDate date) {
return workdayCache.computeIfAbsent(date, d -> {
// 优先检查是否是调休的工作日
if (workWeekends.contains(d)) {
return true;
}
// 检查是否是节假日
if (holidays.contains(d)) {
return false;
}
// 检查是否是周末
DayOfWeek dayOfWeek = d.getDayOfWeek();
return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
});
}
这个方法:
- 首先检查缓存中是否有该日期的判断结果
- 如果没有,则计算:
- 先检查是否是调休工作日(周末但需要上班)
- 再检查是否是节假日
- 最后检查是否是普通周末
- 将结果存入缓存并返回
formatDurationBetween - 计算两个日期时间之间的时间差
public String formatDurationBetween(LocalDateTime start, LocalDateTime end) {
Duration duration = Duration.between(start, end);
long hours = duration.toHours();
long minutes = duration.minusHours(hours).toMinutes();
return String.format("%d小时%d分钟", hours, minutes);
}
这个方法:
- 计算两个时间点之间的Duration
- 提取小时部分
- 从剩余时间中提取分钟部分
- 返回格式化的字符串(如"3小时15分钟")
日期转换方法
public static LocalDate toLocalDate(Date date) {
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
}
public static LocalDateTime toLocalDateTime(Date date) {
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}
public static Date toDate(LocalDate localDate) {
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
}
这些方法用于新旧日期API之间的转换:
toLocalDate:将旧版Date转换为LocalDatetoLocalDateTime:将旧版Date转换为LocalDateTimetoDate:将LocalDate转换为旧版Date
总结
这个WorkdayCalculator类提供了完整的工作日计算功能,主要特点包括:
- 支持节假日和调休工作日的自定义配置
- 使用缓存提高重复计算的性能
- 线程安全的设计(使用ConcurrentHashMap)
- 提供了多种日期时间转换方法
- 支持工作日计算、工作日统计等功能
使用示例:
List<String> holidays = Arrays.asList("2023-10-01", "2023-10-02");
List<String> workWeekends = Arrays.asList("2023-09-30");
WorkdayCalculator calculator = new WorkdayCalculator(holidays, workWeekends);
// 计算5个工作日后的日期
LocalDate start = LocalDate.of(2023, 9, 25);
LocalDate result = calculator.calculateWorkdayAfter(start, 5);
// 统计两个日期间的工作日和节假日
Map<String, Long> counts = calculator.countWorkdaysAndHolidays(
LocalDate.of(2023, 9, 1),
LocalDate.of(2023, 9, 30)
);
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)