add 新增工作日工具类

This commit is contained in:
AprilWind 2024-08-08 15:13:04 +08:00
parent f03c00b2c1
commit b1f846dc52

View File

@ -0,0 +1,174 @@
package org.dromara.common.core.utils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.*;
/**
* 工作日工具类
*
* @author AprilWind
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class WorkDaysUtils {
private static final Map<Integer, Integer[]> DAYS_IN_YEARS = new HashMap<>();
/**
* 计算两个日期之间的工作日天数
*
* @param start 开始日期
* @param end 结束日期
* @return 实际工作日天数
*/
public static int calculateWorkDays(Date start, Date end) {
if (start.after(end)) {
throw new IllegalArgumentException("开始日期不能晚于结束日期");
}
int workDays = 0;
// 获取开始和结束日期的年份
int startYear = getYear(start);
int endYear = getYear(end);
// 如果在同一年
if (startYear == endYear) {
//开始日期年份天
Integer[] daysArray = daysInYear(startYear);
for (int i = getDayOfYearIndex(start); i <= getDayOfYearIndex(end); i++) {
if (daysArray[i] == 0) {
workDays++;
}
}
} else {//跨年
// 处理开始年份
Integer[] startYearDaysArray = daysInYear(startYear);
int startIndex = getDayOfYearIndex(start);
for (int i = startIndex; i < startYearDaysArray.length; i++) {
if (startYearDaysArray[i] == 0) {
workDays++;
}
}
// 处理结束年份
Integer[] endYearDaysArray = daysInYear(endYear);
int endIndex = getDayOfYearIndex(end);
for (int i = 0; i <= endIndex; i++) {
if (endYearDaysArray[i] == 0) {
workDays++;
}
}
// 处理中间的完整年份
for (int year = startYear + 1; year < endYear; year++) {
Integer[] fullYearDaysArray = daysInYear(year);
for (Integer integer : fullYearDaysArray) {
if (integer == 0) {
workDays++;
}
}
}
}
return workDays;
}
/**
* 获取指定年份的天数数组如果指定年份的数据不存在则生成并缓存数据
*
* @param year 指定年份
* @return 表示一年中每一天的状态数组0 表示工作日1 表示周末
*/
private static Integer[] daysInYear(Integer year) {
if (DAYS_IN_YEARS.containsKey(year)) {
return DAYS_IN_YEARS.get(year);
} else {
// 如果年份数据不存在则生成指定年份的数据
Integer[] daysArray = generateDaysArray(year);
DAYS_IN_YEARS.put(year, daysArray);
return daysArray;
}
}
/**
* 根据指定年份生成天数数组其中工作日用 0 表示周末用 1 表示
*
* @param year 指定年份
* @return 表示一年中每一天的状态数组
*/
private static Integer[] generateDaysArray(int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(year, Calendar.JANUARY, 1);
int daysInYear = getDaysInYear(year);
Integer[] daysArray = new Integer[daysInYear];
for (int i = 0; i < daysInYear; i++) {
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
daysArray[i] = (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY) ? 1 : 0;
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
//todo 更新节假日
return updateDaysArray(daysArray, new ArrayList<>());
}
/**
* 根据节假日下标更新 daysArray将对应下标的值改为1
*
* @param daysArray 原始的天数数组
* @param holidays 节假日日期列表
* @return 更新后的天数数组
*/
private static Integer[] updateDaysArray(Integer[] daysArray, List<Date> holidays) {
if (holidays == null || holidays.isEmpty()) {
return daysArray;
}
// 遍历节假日下标数组将对应的 daysArray 元素设置为1
for (Date holiday : holidays) {
int index = getDayOfYearIndex(holiday);
// 确保下标在有效范围内
if (index >= 0 && index < daysArray.length) {
daysArray[index] = 1;
}
}
return daysArray;
}
/**
* 获取日期在一年中的下标天数
*
* @param date 指定日期
* @return 日期在该年份的下标天数
*/
private static int getDayOfYearIndex(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
return dayOfYear - 1;
}
/**
* 获取指定日期的年份
*
* @param date 指定日期
* @return 年份
*/
private static int getYear(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar.get(Calendar.YEAR);
}
/**
* 获取指定年份的天数
*
* @param year 指定年份
* @return 年份中的天数
*/
private static int getDaysInYear(int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(year, Calendar.DECEMBER, 31);
return calendar.get(Calendar.DAY_OF_YEAR);
}
}