记录一下根据时间区间计算工作时间,同时去掉节假日周六日
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.util.ArrayList;
import java.util.List;
/**
* 工作时间计算
*
* @author
* @description:
* @date
*/
public class WorkTimeCalculate {
/**
* 上班时间
*/
private static final LocalTime WORKING_START_TIME = LocalTime.of(9, 0);
/**
* 下班时间
*/
private static final LocalTime WORKING_END_TIME = LocalTime.of(17, 0);
/**
* 午休开始时间
*/
private static final LocalTime NOON_BREAK_START_TIME = LocalTime.of(12, 0);
/**
* 午休结束时间
*/
private static final LocalTime NOON_BREAK_END_TIME = LocalTime.of(14, 0);
/**
* 调休日:非周末但是休息的日期列表
*/
private static final List<LocalDate> holidays = new ArrayList<>();
/**
* 补班日:周末但是上班的日期
*/
private static final List<LocalDate> workdays = new ArrayList();
//初始化调休日和补班日 后面可考虑从数据库查
static {
//调休日
holidays.add(LocalDate.of(2022, 1, 3));
holidays.add(LocalDate.of(2022, 1, 31));
holidays.add(LocalDate.of(2022, 2, 1));
holidays.add(LocalDate.of(2022, 2, 2));
holidays.add(LocalDate.of(2022, 2, 3));
holidays.add(LocalDate.of(2022, 2, 4));
holidays.add(LocalDate.of(2022, 4, 4));
holidays.add(LocalDate.of(2022, 4, 5));
holidays.add(LocalDate.of(2022, 5, 2));
holidays.add(LocalDate.of(2022, 5, 3));
holidays.add(LocalDate.of(2022, 5, 4));
holidays.add(LocalDate.of(2022, 6, 3));
holidays.add(LocalDate.of(2022, 9, 12));
holidays.add(LocalDate.of(2022, 10, 3));
holidays.add(LocalDate.of(2022, 10, 4));
holidays.add(LocalDate.of(2022, 10, 5));
holidays.add(LocalDate.of(2022, 10, 6));
holidays.add(LocalDate.of(2022, 10, 7));
holidays.add(LocalDate.of(2023, 1, 2));
holidays.add(LocalDate.of(2023, 1, 23));
holidays.add(LocalDate.of(2023, 1, 24));
holidays.add(LocalDate.of(2023, 1, 25));
holidays.add(LocalDate.of(2023, 1, 26));
holidays.add(LocalDate.of(2023, 1, 27));
holidays.add(LocalDate.of(2023, 4, 5));
holidays.add(LocalDate.of(2023, 5, 1));
holidays.add(LocalDate.of(2023, 5, 2));
holidays.add(LocalDate.of(2023, 5, 3));
holidays.add(LocalDate.of(2023, 6, 22));
holidays.add(LocalDate.of(2023, 6, 23));
holidays.add(LocalDate.of(2023, 9, 29));
holidays.add(LocalDate.of(2023, 10, 2));
holidays.add(LocalDate.of(2023, 10, 3));
holidays.add(LocalDate.of(2023, 10, 4));
holidays.add(LocalDate.of(2023, 10, 5));
holidays.add(LocalDate.of(2023, 10, 6));
//补班日
workdays.add(LocalDate.of(2022, 1, 29));
workdays.add(LocalDate.of(2022, 1, 30));
workdays.add(LocalDate.of(2022, 4, 2));
workdays.add(LocalDate.of(2022, 4, 24));
workdays.add(LocalDate.of(2022, 5, 7));
workdays.add(LocalDate.of(2022, 10, 8));
workdays.add(LocalDate.of(2022, 10, 9));
workdays.add(LocalDate.of(2023, 1, 28));
workdays.add(LocalDate.of(2023, 1, 29));
workdays.add(LocalDate.of(2023, 4, 23));
workdays.add(LocalDate.of(2023, 5, 6));
workdays.add(LocalDate.of(2023, 6, 25));
workdays.add(LocalDate.of(2023, 10, 7));
workdays.add(LocalDate.of(2023, 10, 8));
}
public static BigDecimal getWorkTime(LocalDateTime startDateTime, LocalDateTime endDateTime,List<LocalDate> holidays,List<LocalDate> workdays) {
if (startDateTime.compareTo(endDateTime) > 0) {
throw new RuntimeException("参数错误,开始时间大于结束时间。");
}
int diff = 0;
while (true) {
//休息日 开始时间后移至第二天的开始工作时间
while (needPass(startDateTime,holidays,workdays)) {
startDateTime = LocalDateTime.of(startDateTime.toLocalDate(), WORKING_START_TIME).plusDays(1);
}
//休息日 结束时间后移至第二天的开始工作时间
while (needPass(endDateTime,holidays,workdays)) {
endDateTime = LocalDateTime.of(endDateTime.toLocalDate(), WORKING_START_TIME).plusDays(1);
}
// 跨天处理
if (startDateTime.getDayOfYear() == endDateTime.getDayOfYear()) {
int diffSecond = getDiffSecond(startDateTime, endDateTime);
diff = diffSecond + diff;
break;
}
int diffSecond = getDiffSecond(startDateTime, LocalDateTime.of(startDateTime.toLocalDate(), WORKING_END_TIME));
diff = diffSecond + diff;
startDateTime = LocalDateTime.of(startDateTime.toLocalDate(), WORKING_START_TIME).plusDays(1);
}
BigDecimal day = new BigDecimal(diff).divide(new BigDecimal(6 * 60*60), 2, RoundingMode.HALF_UP);
// System.out.println("DIFF(hours): " + day+ "天");
return day;
}
private static int getDiffSecond(LocalDateTime startDateTime, LocalDateTime endDateTime) {
LocalTime startTime = startDateTime.toLocalTime();
LocalTime endTime = endDateTime.toLocalTime();
// diff单位:秒
int diff = 0;
// 开始时间切移
if (startTime.isBefore(WORKING_START_TIME)) {
startTime = WORKING_START_TIME;
} else if (startTime.isAfter(NOON_BREAK_START_TIME) && startTime.isBefore(NOON_BREAK_END_TIME)) {
startTime = NOON_BREAK_START_TIME;
} else if (startTime.isAfter(WORKING_END_TIME)) {
startTime = WORKING_END_TIME;
}
// 结束时间切移
if (endTime.isBefore(WORKING_START_TIME)) {
endTime = WORKING_START_TIME;
} else if (endTime.isAfter(NOON_BREAK_START_TIME) && endTime.isBefore(NOON_BREAK_END_TIME)) {
endTime = NOON_BREAK_START_TIME;
} else if (endTime.isAfter(WORKING_END_TIME)) {
endTime = WORKING_END_TIME;
}
// 午休时间判断处理
if (startTime.compareTo(NOON_BREAK_START_TIME) <= 0 && endTime.compareTo(NOON_BREAK_END_TIME) >= 0) {
diff = diff + (NOON_BREAK_END_TIME.toSecondOfDay()-NOON_BREAK_START_TIME.toSecondOfDay());
}
diff = endTime.toSecondOfDay() - startTime.toSecondOfDay() - diff;
return diff;
}
/**
* 计算两个时间之间的天数 每天按24小数计算 不考虑上下班 不足一天的部分保留两位小数
* 特殊情况:开始时间在休息日,则开始时间按下个工作日的00:00:00开始计算
* 特殊情况:结束时间在休息日,则结束时间按上个工作日的13:59:59开始计算
*
* @param startDateTime
* @param endDateTime
* @return
*/
public static BigDecimal getWorkDays(LocalDateTime startDateTime, LocalDateTime endDateTime,List<LocalDate> holidays,List<LocalDate> workdays) {
if (startDateTime.compareTo(endDateTime) > 0) {
throw new RuntimeException("参数错误,开始时间大于结束时间。");
}
int fullDays = 0;
long minute = 0;
//特殊情况:开始时间在休息日,则开始时间按下个工作日的00:00:00开始计算
if (needPass(startDateTime,holidays,workdays)) {
startDateTime = startDateTime.toLocalDate().atStartOfDay().plusDays(1);
}
//特殊情况:结束时间在休息日,则结束时间按上个工作日的13:59:59开始计算
if (needPass(endDateTime,holidays,workdays)) {
endDateTime = endDateTime.toLocalDate().atStartOfDay();
}
while (startDateTime.compareTo(endDateTime) < 0) {
while (needPass(startDateTime,holidays,workdays)) {
startDateTime = startDateTime.plusDays(1);
}
while (needPass(endDateTime,holidays,workdays)) {
endDateTime = endDateTime.plusDays(1);
}
if (startDateTime.getDayOfYear() == endDateTime.getDayOfYear()) {
// 按分钟计算
minute = Duration.between(startDateTime, endDateTime).toMinutes();
break;
}
startDateTime = startDateTime.plusDays(1);
fullDays += 1;
}
//折算不足一天的时间
BigDecimal oddDay = new BigDecimal(minute).divide(new BigDecimal(8 * 60), 2, RoundingMode.HALF_UP);
return new BigDecimal(fullDays).add(oddDay);
}
public static BigDecimal getWorkDays(LocalDateTime startDateTime, LocalDateTime endDateTime) {
if (startDateTime.compareTo(endDateTime) > 0) {
throw new RuntimeException("参数错误,开始时间大于结束时间。");
}
int fullDays = 0;
long minute = 0;
while (startDateTime.compareTo(endDateTime) < 0) {
if (startDateTime.getDayOfYear() == endDateTime.getDayOfYear()) {
// 按分钟计算
minute = Duration.between(startDateTime, endDateTime).toMinutes();
break;
}
startDateTime = startDateTime.plusDays(1);
fullDays += 1;
}
//折算不足一天的时间
BigDecimal oddDay = new BigDecimal(minute).divide(new BigDecimal(24 * 60), 2, RoundingMode.HALF_UP);
return new BigDecimal(fullDays).add(oddDay);
}
/**
* 当天休息还是工作
*
* @param time
* @return
*/
private static boolean needPass(LocalDateTime time,List<LocalDate> holidays,List<LocalDate> workdays) {
if (time.getDayOfWeek() == DayOfWeek.SATURDAY || time.getDayOfWeek() == DayOfWeek.SUNDAY) {
if (isWorkday(time,workdays)) {
return false;
}
return true;
} else {
if (isHoliday(time,holidays)) {
return true;
}
return false;
}
}
/**
* 是否调休日
*
* @param time
* @return
*/
private static boolean isHoliday(LocalDateTime time,List<LocalDate> holidays) {
LocalDate date = time.toLocalDate();
if (holidays.contains(date)) {
return true;
}
return false;
}
/**
* 是否补班日
*
* @param time
* @return
*/
private static boolean isWorkday(LocalDateTime time, List<LocalDate> workdays) {
LocalDate date = time.toLocalDate();
if (workdays.contains(date)) {
return true;
}
return false;
}
public static void main(String[] args) {
LocalDateTime startDateTime= LocalDateTime.of(2024, 6, 28, 9, 0, 0);
LocalDateTime endDateTime= LocalDateTime.of(2024, 6, 28, 12, 0, 0);
WorkTimeCalculate.getWorkTime(startDateTime,endDateTime, new ArrayList<>(), new ArrayList<>());
System.out.println(WorkTimeCalculate.getWorkDays(startDateTime,endDateTime, new ArrayList<>(), new ArrayList<>()));
LocalDateTime date1 = LocalDateTime.of(2024, 6, 1,0, 00, 0);
LocalDateTime date2 = LocalDateTime.of(2024, 6, 30,23, 59, 59);
System.out.println(WorkTimeCalculate.getWorkDays(date1,date2));
}
}