You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
weaver-ningbojinghua/src/com/engine/kq/job/UpdateEffectiveDuration.java

385 lines
18 KiB
Java

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.engine.kq.job;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.engine.kq.biz.KQShiftManagementComInfo;
import com.engine.kq.biz.KQShiftRestTimeSectionComInfo;
import com.engine.kq.biz.KQWorkTime;
import com.engine.kq.entity.WorkTimeEntity;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import weaver.common.DateUtil;
import weaver.conn.RecordSet;
import weaver.general.BaseBean;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
/**
* @author:dxfeng
* @createTime: 2024/03/29
* @version: 1.0
*/
public class UpdateEffectiveDuration {
/**
* 日期时间格式化
*/
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/**
* 有效时长计算逻辑:
* 1、最早、最晚打卡时间与开始时间、结束时间没有交集=》有效时长=共计时长
* 2、最早、最晚打卡时间与开始时间、结束时间有交集=》
* 1比较最早打卡时间与开始时间如果最早打卡时间晚于开始时间统计晚打卡的分钟数
* 2比较最晚打卡时间与结束时间如果最晚打卡时间早于结束时间统计早打卡的分钟数
* 3统计相差的分钟数按半小时起算有效时长=共计时长-相差时长
*
* @param mainId
* @param userId
* @param gzrq
* @param earlyStartTime
* @param afterEndTime
* @param startTime
* @param endTime
*/
public static void execute(String mainId, String userId, String gzrq, String earlyStartTime, String afterEndTime, String startTime, String endTime) {
RecordSet recordSet = new RecordSet();
try {
LocalDateTime startSignTime = LocalDateTime.parse(earlyStartTime, DATE_TIME_FORMATTER);
LocalDateTime endSignTime = LocalDateTime.parse(afterEndTime, DATE_TIME_FORMATTER);
LocalDateTime startWorkTime = LocalDateTime.parse(startTime, DATE_TIME_FORMATTER);
LocalDateTime endWorkTime = LocalDateTime.parse(endTime, DATE_TIME_FORMATTER);
// 最早、最晚打卡时间,与开始时间、结束时间,是否存在交集
boolean hasIntersection = startSignTime.isBefore(endWorkTime) && endSignTime.isAfter(startWorkTime);
recordSet.executeQuery("select gjsc from uf_jbtz where id = ?", mainId);
double gjscHours = 0.0;
if (recordSet.next()) {
gjscHours = recordSet.getDouble("gjsc");
}
if (gjscHours < 0) {
throw new Exception("mainId===" + mainId + ",共计时长小于0");
}
if (hasIntersection) {
int totalMinutes = 0;
if (startSignTime.isAfter(startWorkTime)) {
int startDifference = (int) (startWorkTime.until(startSignTime, ChronoUnit.MINUTES));
recordSet.execute("mainId=" + mainId + ",userId=" + userId + ",gzrq=" + gzrq + ",startDifference=" + startDifference);
totalMinutes += startDifference;
}
if (endSignTime.isBefore(endWorkTime)) {
int endDifference = (int) (endSignTime.until(endWorkTime, ChronoUnit.MINUTES));
recordSet.execute("mainId=" + mainId + ",userId=" + userId + ",gzrq=" + gzrq + ",endDifference=" + endDifference);
totalMinutes += endDifference;
}
// 总计相差时间,按照半小时,向上取整
double totalHours = (double) totalMinutes / 60;
double timeDifference = gjscHours - totalHours;
// 将小时数按照0.5小时的单位向下取整
double roundedHours = (int) Math.floor(timeDifference / 0.5) * 0.5;
recordSet.writeLog("userId==" + userId + ",totalMinutes===" + totalMinutes + ",gjscHours===" + gjscHours + ",totalHours==" + totalHours + ",roundedHours==" + roundedHours);
recordSet.executeUpdate("update uf_jbtz set yxsc=? where id=? ", roundedHours, mainId);
} else {
// 最早、最晚打卡时间,与开始时间、结束时间没有交集=》有效时长=共计时长
recordSet.executeUpdate("update uf_jbtz set yxsc=? where id=? ", gjscHours, mainId);
}
} catch (Exception e) {
recordSet.writeLog(e);
}
}
/**
* 更新加班台账表,有效时长字段
* <p/>
* <p>导入的加班数据增加根据班次的最早最晚打卡时间取交集,按照系统的加班单和打卡数据取交集处理</p>
*
* @param mainId 当前数据ID
* @param userId 加班人ID
* @param gzrq 归属日志
* @param earlyStartTime 最早打卡时间
* @param afterEndTime 最晚打卡时间
*/
public static void execute1(String mainId, String userId, String gzrq, String earlyStartTime, String afterEndTime, String startTime, String endTime) {
RecordSet recordSet = new RecordSet();
try {
KQWorkTime kqWorkTime = new KQWorkTime();
WorkTimeEntity workTimeEntity = kqWorkTime.getWorkTime(userId, gzrq);
String serialId = workTimeEntity.getSerialId();
recordSet.writeLog("serialId===" + serialId);
if (StringUtils.isBlank(serialId) || "-1".equals(serialId)) {
kqWorkTime.setIsFormat(true);
workTimeEntity = kqWorkTime.getWorkTime(userId, gzrq);
serialId = workTimeEntity.getSerialId();
}
recordSet.writeLog("userId==" + userId + ",serialId===" + JSON.toJSONString(serialId) + ",workTimeEntity===" + JSON.toJSONString(workTimeEntity));
// 转换所有的工作时间
List<Map<String, String>> workTimeList = new ArrayList<>();
Map<String, String> workMap = new HashMap<>();
workMap.put("startTimes", startTime);
workMap.put("endTimes", endTime);
workTimeList.add(workMap);
recordSet.writeLog("userId==" + userId + ",workTimeList===" + JSON.toJSONString(workTimeList));
// 转换所有的休息时间
List<Map<String, String>> restTimeList = new ArrayList<>();
KQShiftManagementComInfo kqShiftManagementComInfo = new KQShiftManagementComInfo();
String isRestTimeOpen = kqShiftManagementComInfo.getIsresttimeopen(serialId);
// 排除休息时间是否开启 1表示开启
recordSet.writeLog("isRestTimeOpen===" + isRestTimeOpen);
if ("1".equals(isRestTimeOpen)) {
List<Object> restSectionTimes = new KQShiftRestTimeSectionComInfo().getRestSectionTimes(serialId);
recordSet.writeLog("userId==" + userId + ",restSectionTimes===" + JSON.toJSONString(restSectionTimes));
if (CollectionUtils.isNotEmpty(restSectionTimes)) {
//convertDateTime(gzrq, restSectionTimes, restTimeList);
convertDateTime2(gzrq, restSectionTimes, restTimeList);
recordSet.writeLog("userId==" + userId + ",restTimeList===" + JSON.toJSONString(restTimeList));
}
}
// 所有的有效时间区间
recordSet.writeLog("userId==" + userId + ",earlyStartTime===" + earlyStartTime + ",afterEndTime===" + afterEndTime);
List<String> effectiveTime = getEffectiveTime(earlyStartTime, afterEndTime, startTime, endTime, restTimeList);
recordSet.writeLog("userId==" + userId + ",effectiveTime===" + JSON.toJSONString(effectiveTime));
// 有效区间总计分钟数
long totalMinutes = effectiveTime.stream()
.mapToInt(interval -> {
String[] parts = interval.split(",");
LocalDateTime start = LocalDateTime.parse(parts[0], DATE_TIME_FORMATTER);
LocalDateTime end = LocalDateTime.parse(parts[1], DATE_TIME_FORMATTER);
return (int) (start.until(end, ChronoUnit.MINUTES));
})
.sum();
double totalHours = (double) totalMinutes / 60;
// 将小时数按照0.5小时的单位向下取整
double roundedHours = (int) Math.floor(totalHours / 0.5) * 0.5;
recordSet.writeLog("userId==" + userId + ",totalMinutes===" + totalMinutes + ",totalHours==" + totalHours + ",roundedHours==" + roundedHours);
// 更新当前数据的有效时长
recordSet.executeUpdate("update uf_jbtz set yxsc=? where id=? ", roundedHours, mainId);
} catch (Exception e) {
recordSet.writeLog(e);
}
}
/**
* 获取有效时长时间区间
*/
private static List<String> getEffectiveTime(String earlyStartTime, String afterEndTime, String startTime, String endTime, List<Map<String, String>> restTimeList) {
// 打卡时间区间,去除所有的休息时间
List<String> effectiveTimeList = new ArrayList<>();
LocalDateTime startSignTime = LocalDateTime.parse(earlyStartTime, DATE_TIME_FORMATTER);
LocalDateTime endSignTime = LocalDateTime.parse(afterEndTime, DATE_TIME_FORMATTER);
LocalDateTime startWorkTime = LocalDateTime.parse(startTime, DATE_TIME_FORMATTER);
LocalDateTime endWorkTime = LocalDateTime.parse(endTime, DATE_TIME_FORMATTER);
// 计算交集
LocalDateTime intersectionStart = startSignTime.isAfter(startWorkTime) ? startSignTime : startWorkTime;
LocalDateTime intersectionEnd = endSignTime.isBefore(endWorkTime) ? endSignTime : endWorkTime;
List<TimeInterval> restIntervals = new ArrayList<>();
for (Map<String, String> restTimeMap : restTimeList) {
restIntervals.add(new TimeInterval(
LocalDateTime.parse(restTimeMap.get("startTimes"), DATE_TIME_FORMATTER),
LocalDateTime.parse(restTimeMap.get("endTimes"), DATE_TIME_FORMATTER)
));
}
// 休息时间区间排序
restIntervals.sort(Comparator.comparing(TimeInterval::getStart));
// 实际的工作开始时间、结束时间
List<TimeInterval> workIntervals = calculateWorkIntervals(intersectionStart, intersectionEnd, restIntervals);
//new BaseBean().writeLog("workIntervals===" + JSON.toJSONString(workIntervals));
for (TimeInterval workInterval : workIntervals) {
effectiveTimeList.add(workInterval.getStart().format(DATE_TIME_FORMATTER) + "," + workInterval.getEnd().format(DATE_TIME_FORMATTER));
}
long totalMinutes = calculateTotalWorkMinutes(workIntervals);
//new BaseBean().writeLog("totalMinutes==="+totalMinutes);
//if (intersectionStart.isBefore(intersectionEnd)) {
// // 去除休息时间
// for (Map<String, String> restTimeMap : restTimeList) {
// LocalDateTime startRestTime = LocalDateTime.parse(restTimeMap.get("startTimes"), DATE_TIME_FORMATTER);
// LocalDateTime endRestTime = LocalDateTime.parse(restTimeMap.get("endTimes"), DATE_TIME_FORMATTER);
//
// if (!intersectionEnd.isBefore(startRestTime) && !intersectionStart.isAfter(endRestTime)) {
// if (intersectionStart.isBefore(startRestTime)) {
// // 交集在休息时间之前
// intersectionEnd = intersectionEnd.isBefore(startRestTime) ? intersectionEnd : startRestTime;
// } else if (intersectionEnd.isAfter(endRestTime)) {
// // 交集在休息时间之后
// intersectionStart = intersectionStart.isAfter(endRestTime) ? intersectionStart : endRestTime;
// } else {
// // 休息时间在交集中间
// intersectionStart = startRestTime;
// intersectionEnd = endRestTime;
// }
// }
// }
// effectiveTimeList.add(intersectionStart.format(DATE_TIME_FORMATTER) + "," + intersectionEnd.format(DATE_TIME_FORMATTER));
//}
return effectiveTimeList;
}
/**
* 转换日期时间
*
* @param gzrq 归属日期
* @param sectionTimes 转换前时间
* @param timeList 转换后日期时间
*/
private static void convertDateTime(String gzrq, List<Object> sectionTimes, List<Map<String, String>> timeList) {
String currentDate = gzrq;
String preTime = "";
for (Object sectionTime : sectionTimes) {
List<Map<String, String>> sectionTime1 = (List) sectionTime;
if (sectionTime1.size() != 2) {
break;
}
// 获取当前的打卡时间
Map<String, String> startMap = sectionTime1.get(0);
String startTimes = startMap.get("times");
Map<String, String> map = new HashMap<>();
currentDate = getDateStr(currentDate, preTime, startTimes);
map.put("startTimes", currentDate + " " + startTimes + ":00");
Map<String, String> endMap = sectionTime1.get(1);
String endTimes = endMap.get("times");
currentDate = getDateStr(currentDate, startTimes, endTimes);
map.put("endTimes", currentDate + " " + endTimes + ":00");
preTime = endTimes;
timeList.add(map);
}
}
private static void convertDateTime2(String gzrq, List<Object> sectionTimes, List<Map<String, String>> timeList) {
String currentDate = gzrq;
String preTime = "";
for (Object sectionTime : sectionTimes) {
List<Map<String, String>> sectionTime1 = (List) sectionTime;
if (sectionTime1.size() != 2) {
break;
}
// 获取当前的打卡时间
Map<String, String> startMap = sectionTime1.get(0);
String startTimes = startMap.get("times");
String startAcross = startMap.get("across");
Map<String, String> map = new HashMap<>();
//currentDate = getDateStr(currentDate, preTime, startTimes);
if ("1".equals(startAcross)) {
map.put("startTimes", DateUtil.addDate(currentDate, 1) + " " + startTimes + ":00");
} else {
map.put("startTimes", currentDate + " " + startTimes + ":00");
}
Map<String, String> endMap = sectionTime1.get(1);
String endTimes = endMap.get("times");
String endAcross = endMap.get("across");
//currentDate = getDateStr(currentDate, startTimes, endTimes);
if ("1".equals(endAcross)) {
map.put("endTimes", DateUtil.addDate(currentDate, 1) + " " + endTimes + ":00");
} else {
map.put("endTimes", currentDate + " " + endTimes + ":00");
}
preTime = endTimes;
timeList.add(map);
}
}
/**
* 组合日期、时间
*
* @param currentDate 当前日期
* @param preTime 之前处理的时间
* @param currentTime 当前需要处理的时间
* @return
*/
private static String getDateStr(String currentDate, String preTime, String currentTime) {
// 前一个时间为空,返回当前日期+当前时间
if (StringUtils.isBlank(preTime)) {
return currentDate;
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
LocalTime localPreTime = LocalTime.parse(preTime, formatter);
LocalTime localCurrentTime = LocalTime.parse(currentTime, formatter);
if (localPreTime.isAfter(localCurrentTime)) {
return DateUtil.addDate(currentDate, 1);
} else {
return currentDate;
}
}
public static List<TimeInterval> calculateWorkIntervals(LocalDateTime startWork, LocalDateTime endWork,
List<TimeInterval> restIntervals) {
List<TimeInterval> workIntervals = new ArrayList<>();
LocalDateTime currentStart = startWork;
for (TimeInterval restInterval : restIntervals) {
LocalDateTime restStart = restInterval.getStart();
LocalDateTime restEnd = restInterval.getEnd();
// 如果休息时间与工作时间重合,则调整工作时间段
if (currentStart.isBefore(restEnd) && endWork.isAfter(restStart)) {
if (currentStart.isBefore(restStart)) {
workIntervals.add(new TimeInterval(currentStart, restStart));
}
currentStart = restEnd;
}
}
// 添加剩余的工作时间段
if (currentStart.isBefore(endWork)) {
workIntervals.add(new TimeInterval(currentStart, endWork));
}
return workIntervals;
}
public static long calculateTotalWorkMinutes(List<TimeInterval> workIntervals) {
long totalMinutes = 0;
for (TimeInterval interval : workIntervals) {
totalMinutes += Duration.between(interval.getStart(), interval.getEnd()).toMinutes();
}
return totalMinutes;
}
static class TimeInterval {
private LocalDateTime start;
private LocalDateTime end;
public TimeInterval(LocalDateTime start, LocalDateTime end) {
this.start = start;
this.end = end;
}
public LocalDateTime getStart() {
return start;
}
public LocalDateTime getEnd() {
return end;
}
}
}