@ -1,17 +1,30 @@
package com.epmet.service.impl ;
import com.epmet.commons.tools.constant.NumConstant ;
import com.epmet.commons.tools.exception.RenException ;
import com.epmet.commons.tools.utils.DateUtils ;
import com.epmet.commons.tools.utils.DateUtils ;
import com.epmet.constant.ProjectConstant ;
import com.epmet.dao.CalenderDao ;
import com.epmet.dto.form.CostDayFormDTO ;
import com.epmet.dto.form.TimestampIntervalFormDTO ;
import com.epmet.dto.form.WorkDayFormDTO ;
import com.epmet.dto.result.CostDayResultDTO ;
import com.epmet.dto.form.WorkMinuteFormDTO ;
import com.epmet.dto.result.WorkDayResultDTO ;
import com.epmet.entity.CalenderEntity ;
import com.epmet.service.WorkDayService ;
import org.apache.commons.lang3.StringUtils ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.beans.factory.annotation.Autowired ;
import org.springframework.stereotype.Service ;
import org.springframework.util.CollectionUtils ;
import java.text.SimpleDateFormat ;
import java.time.LocalDateTime ;
import java.time.ZoneId ;
import java.time.temporal.ChronoUnit ;
import java.util.* ;
/ * *
@ -25,6 +38,8 @@ public class WorkDayServiceImpl implements WorkDayService {
@Autowired
private CalenderDao calenderDao ;
private static SimpleDateFormat format = new SimpleDateFormat ( DateUtils . DATE_PATTERN ) ;
private static SimpleDateFormat formatMinute = new SimpleDateFormat ( DateUtils . DATE_TIME_PATTERN ) ;
@Override
public List < WorkDayResultDTO > detentionDays ( List < WorkDayFormDTO > workDayFormDTO ) {
List < WorkDayResultDTO > list = new ArrayList < > ( ) ;
@ -44,6 +59,95 @@ public class WorkDayServiceImpl implements WorkDayService {
return list ;
}
/ * *
* 工作日计算
*
* @param formDTO
* @return java . util . List < com . epmet . dto . result . CostDayResultDTO >
* @author zhaoqifeng
* @date 2020 / 10 / 21 17 : 56
* /
@Override
public List < CostDayResultDTO > costWorkDays ( List < CostDayFormDTO > formDTO ) {
List < CostDayResultDTO > list = new ArrayList < > ( ) ;
if ( formDTO . isEmpty ( ) ) {
throw new RenException ( "起始时间、终止时间不能为空" ) ;
}
for ( CostDayFormDTO form : formDTO ) {
CostDayResultDTO result = new CostDayResultDTO ( ) ;
result . setId ( form . getId ( ) ) ;
result . setStaffId ( form . getStaffId ( ) ) ;
result . setDetentionDays ( this . getWorkDays ( form . getStartDate ( ) , form . getEndDate ( ) ) ) ;
result . setStartDate ( form . getStartDate ( ) ) ;
list . add ( result ) ;
}
return list ;
}
/ * *
* 日历日计算
*
* @param formDTO
* @return java . util . List < com . epmet . dto . result . CostDayResultDTO >
* @author zhaoqifeng
* @date 2020 / 10 / 21 17 : 56
* /
@Override
public List < CostDayResultDTO > costCalendarDays ( List < CostDayFormDTO > formDTO ) {
List < CostDayResultDTO > list = new ArrayList < > ( ) ;
if ( formDTO . isEmpty ( ) ) {
throw new RenException ( "起始时间、终止时间不能为空" ) ;
}
for ( CostDayFormDTO form : formDTO ) {
CostDayResultDTO result = new CostDayResultDTO ( ) ;
result . setId ( form . getId ( ) ) ;
result . setStaffId ( form . getStaffId ( ) ) ;
result . setDetentionDays ( this . getCalendarDays ( form . getStartDate ( ) , form . getEndDate ( ) ) ) ;
result . setStartDate ( form . getStartDate ( ) ) ;
list . add ( result ) ;
}
return list ;
}
/ * *
* @Description 计算经历的多少分钟 ( 只计算工作日 )
* @param param
* @return java . util . Map < java . lang . String , java . lang . Integer >
* @author wangc
* @date 2020 . 10 . 21 16 : 14
* /
@Override
public Map < String , Integer > workMinutes ( WorkMinuteFormDTO param ) {
List < TimestampIntervalFormDTO > params = param . getTimeList ( ) ;
if ( CollectionUtils . isEmpty ( params ) ) return null ;
Map < String , Integer > result = new LinkedHashMap < > ( ) ;
//默认非精准计算
if ( StringUtils . isBlank ( param . getIfPrecise ( ) ) | | ! StringUtils . equals ( ProjectConstant . PRECISE_CALCULATION , param . getIfPrecise ( ) ) ) {
params . forEach ( local - > {
result . put ( local . getId ( ) , calculateImpreciseDetentionMinutes ( local . getLeft ( ) , local . getRight ( ) ) ) ;
} ) ;
return result ;
}
//精准计算
if ( StringUtils . isBlank ( param . getIfCustom ( ) ) | | ! StringUtils . equals ( ProjectConstant . CALCULATION_TYPE_CUSTOM , param . getIfCustom ( ) ) ) {
//默认
params . forEach ( local - > {
result . put ( local . getId ( ) , calculateDetentionMinutes ( local . getLeft ( ) , local . getRight ( ) ) ) ;
} ) ;
} else {
//自定义
params . forEach ( local - > {
try {
result . put ( local . getId ( ) , calculateDetentionMinutesWithStartEnd ( local . getLeft ( ) , local . getRight ( ) , param . getStartTemplate ( ) , param . getEndTemplate ( ) ) ) ;
} catch ( Exception e ) {
throw new RenException ( e . getMessage ( ) ) ;
}
} ) ;
}
return result ;
}
//公式: 当前日期 - 被吹日期 - 期间的节假日
private String caculateDetentionDays ( String startDateStr , String endDateStr ) {
if ( startDateStr . equals ( endDateStr ) ) {
@ -77,6 +181,249 @@ public class WorkDayServiceImpl implements WorkDayService {
return "-1" ;
}
/ * * *
* @Description 计算两个日期之间的非准确时间差 ( 只包括工作日 ) , 单位 : 分钟 不足一天按照一天计算
* @param left
* @param right
* @return java . lang . Integer
* @author wangc
* @date 2020 . 10 . 21 17 : 09
* /
private Integer calculateImpreciseDetentionMinutes ( Date left , Date right ) {
if ( null = = left ) { logger . error ( "计算工作日,传入的开始日期为空!" ) ; return null ; }
//给右区间赋值,默认当前时间
if ( null = = right | | right . compareTo ( left ) < NumConstant . ZERO ) right = new Date ( ) ;
List < CalenderEntity > list = calenderDao . selectByStartAndEnd ( format . format ( left ) , format . format ( right ) ) ;
if ( ! CollectionUtils . isEmpty ( list ) ) {
//集合中只有一个元素,说明两个时间在同一天
if ( list . size ( ) = = NumConstant . ONE ) {
return NumConstant . EIGHT * NumConstant . SIXTY ;
}
//集合中有两个元素,说明两个时间是相连的
//集合中有两个元素以上,说明两个时间存在跨度
else {
int costMin = NumConstant . ZERO ;
if ( NumConstant . TWO = = list . size ( ) ) return costMin ;
for ( int index = NumConstant . ZERO ; index < list . size ( ) ; index + + )
if ( StringUtils . equals ( ProjectConstant . DAY_TYPE_WORK , list . get ( index ) . getType ( ) ) )
costMin + = NumConstant . TWENTY_FOUR * NumConstant . SIXTY ;
return costMin ;
}
}
logger . warn ( "计算工作日,没有找到开始日期和结束日期,可能数据库中没有存储对应时段的数据,开始时间:{},结束时间:{}" , left , right ) ;
return null ;
}
/ * *
* @Description 计算两个日期之间的时间差 ( 只包括工作日 ) , 单位 : 分钟
* @param left
* @param right
* @return java . lang . Integer
* @author wangc
* @date 2020 . 10 . 21 14 : 00
* /
private Integer calculateDetentionMinutes ( Date left , Date right ) {
if ( null = = left ) { logger . error ( "计算工作日,传入的开始日期为空!" ) ; return null ; }
//给右区间赋值,默认当前时间
if ( null = = right | | right . compareTo ( left ) < NumConstant . ZERO ) right = new Date ( ) ;
List < CalenderEntity > list = calenderDao . selectByStartAndEnd ( format . format ( left ) , format . format ( right ) ) ;
if ( ! CollectionUtils . isEmpty ( list ) ) {
//集合中只有一个元素,说明两个时间在同一天
if ( list . size ( ) = = NumConstant . ONE ) {
if ( ProjectConstant . DAY_TYPE_WORK . equals ( list . get ( NumConstant . ZERO ) . getType ( ) ) )
return ( int ) ( ( right . getTime ( ) - left . getTime ( ) ) / NumConstant . ONE_THOUSAND / NumConstant . SIXTY ) ;
else {
logger . warn ( "计算工作日,传入的起始时间都在同一天且是在节假日,开始时间:{},结束时间:{},节日类型:{}(1工作日、2周末、3、节假日)" , left , right ) ;
return NumConstant . ZERO ;
}
}
//集合中有两个元素,说明两个时间是相连的
//集合中有两个元素以上,说明两个时间存在跨度
else {
String leftType = list . get ( NumConstant . ZERO ) . getType ( ) ;
String rightType = list . get ( list . size ( ) - NumConstant . ONE ) . getType ( ) ;
int costMin = NumConstant . ZERO ;
if ( ProjectConstant . DAY_TYPE_WORK . equals ( leftType ) ) {
LocalDateTime localDateTime = LocalDateTime . ofInstant ( left . toInstant ( ) , ZoneId . systemDefault ( ) ) ;
//获取第第二天零点时刻的实例
LocalDateTime tomorrowTime = LocalDateTime . ofInstant ( left . toInstant ( ) , ZoneId . systemDefault ( ) )
. plusDays ( NumConstant . ONE ) . withHour ( NumConstant . ZERO ) . withMinute ( NumConstant . ZERO ) . withSecond ( NumConstant . ZERO ) . withNano ( NumConstant . ZERO ) ;
//ChronoUnit日期枚举类,between方法计算两个时间对象之间的时间量
costMin + = ChronoUnit . SECONDS . between ( localDateTime , tomorrowTime ) / NumConstant . SIXTY ;
}
if ( ProjectConstant . DAY_TYPE_WORK . equals ( rightType ) ) {
LocalDateTime localDateTime = LocalDateTime . ofInstant ( right . toInstant ( ) , ZoneId . systemDefault ( ) ) ;
//获取第第二天零点时刻的实例
LocalDateTime initialTime = LocalDateTime . ofInstant ( right . toInstant ( ) , ZoneId . systemDefault ( ) )
. withHour ( NumConstant . ZERO ) . withMinute ( NumConstant . ZERO ) . withSecond ( NumConstant . ZERO ) . withNano ( NumConstant . ZERO ) ;
//ChronoUnit日期枚举类,between方法计算两个时间对象之间的时间量
costMin + = ChronoUnit . SECONDS . between ( localDateTime , initialTime ) / NumConstant . SIXTY ;
}
if ( NumConstant . TWO = = list . size ( ) ) return costMin ;
for ( int index = NumConstant . ONE ; index < list . size ( ) - NumConstant . ONE ; index + + )
if ( StringUtils . equals ( ProjectConstant . DAY_TYPE_WORK , list . get ( index ) . getType ( ) ) )
costMin + = NumConstant . TWENTY_FOUR * NumConstant . SIXTY ;
return costMin ;
}
}
logger . warn ( "计算工作日,没有找到开始日期和结束日期,可能数据库中没有存储对应时段的数据,开始时间:{},结束时间:{}" , left , right ) ;
return null ;
}
/ * * *
* @Description 根据可配置的工作起始时间计算两个日期之间的差
* @param left
* @param right
* @param start 格式为 HH : mm : ss
* @param end 格式为 HH : mm : ss
* @return java . lang . Integer
* @author wangc
* @date 2020 . 10 . 20 18 : 05
* /
private Integer calculateDetentionMinutesWithStartEnd ( Date left , Date right , String start , String end ) throws Exception {
if ( null = = left ) { logger . error ( "计算工作日,传入的开始日期为空!" ) ; return null ; }
if ( null = = start | | null = = end ) { start = "9:00:00" ; end = "17:00:00" ; }
//给右区间赋值,默认当前时间
if ( null = = right | | right . compareTo ( left ) < NumConstant . ZERO ) right = new Date ( ) ;
//自定义起始时间
String standardStartDateStr = format . format ( left ) . concat ( " " ) . concat ( start ) ;
//自定义截至时间
String standardEndDateStr = format . format ( right ) . concat ( " " ) . concat ( end ) ;
Date standardStartDate = formatMinute . parse ( standardStartDateStr ) ;
Date standardEndDate = formatMinute . parse ( standardEndDateStr ) ;
if ( standardEndDate . compareTo ( standardStartDate ) < NumConstant . ZERO ) { logger . error ( "计算工作日,自定义截止日期小于自定义起始日期!" ) ; return null ; }
//单位时间内规定起止时间的时间差
Integer delta_T = ( int ) ( standardEndDate . getTime ( ) - formatMinute . parse ( format . format ( right ) . concat ( " " ) . concat ( start ) ) . getTime ( ) ) / NumConstant . ONE_THOUSAND / NumConstant . SIXTY ;
List < CalenderEntity > list = calenderDao . selectByStartAndEnd ( format . format ( left ) , format . format ( right ) ) ;
if ( ! CollectionUtils . isEmpty ( list ) ) {
//集合中只有一个元素,说明两个时间在同一天
if ( list . size ( ) = = NumConstant . ONE ) {
if ( ProjectConstant . DAY_TYPE_WORK . equals ( list . get ( NumConstant . ZERO ) . getType ( ) ) ) {
//开始时间早于当天规定开始时间
if ( left . before ( standardStartDate ) ) {
if ( right . before ( standardStartDate ) ) {
//结束时间早于当天规定开始时间
logger . warn ( "计算工作日,开始时间与结数时间均早于当天规定的起止计算时间,开始时间:{},结束时间:{},当天开始时间:{}" , left , right , standardStartDate ) ;
return NumConstant . ZERO ;
} else if ( right . before ( standardEndDate ) ) {
return ( int ) ( right . getTime ( ) - standardStartDate . getTime ( ) ) / NumConstant . ONE_THOUSAND / NumConstant . SIXTY ;
} else {
//结束时间晚于当天规定截止时间
return delta_T ;
}
} else if ( left . before ( standardEndDate ) ) {
//开始时间在当天规定起止时间之间
if ( right . before ( standardEndDate ) ) {
return ( int ) ( right . getTime ( ) - left . getTime ( ) ) / NumConstant . ONE_THOUSAND / NumConstant . SIXTY ;
} else {
return ( int ) ( standardEndDate . getTime ( ) - left . getTime ( ) ) / NumConstant . ONE_THOUSAND / NumConstant . SIXTY ;
}
} else {
logger . warn ( "计算工作日,开始时间与结数时间晚于当天规定的截止计算时间,开始时间:{},结束时间:{},当天截止时间:{}" , left , right , standardEndDate ) ;
return NumConstant . ZERO ;
}
} else {
logger . warn ( "计算工作日,传入的起始时间都在同一天且是在节假日,开始时间:{},结束时间:{},节日类型:{}(1工作日、2周末、3、节假日)" , left , right ) ;
return NumConstant . ZERO ;
}
}
//集合中有两个元素,说明两个时间是相连的
//集合中有两个元素以上,说明两个时间存在跨度
else {
String leftType = list . get ( NumConstant . ZERO ) . getType ( ) ;
String rightType = list . get ( list . size ( ) - NumConstant . ONE ) . getType ( ) ;
int costMin = NumConstant . ZERO ;
if ( ProjectConstant . DAY_TYPE_WORK . equals ( leftType ) ) {
if ( left . before ( standardStartDate ) ) {
costMin + = delta_T ;
} else if ( left . before ( standardEndDate ) ) {
costMin + = ( formatMinute . parse ( format . format ( left ) . concat ( " " ) . concat ( end ) ) . getTime ( ) - left . getTime ( ) ) / NumConstant . ONE_THOUSAND / NumConstant . SIXTY ;
} else {
}
}
if ( ProjectConstant . DAY_TYPE_WORK . equals ( rightType ) ) {
Date leftStandardStartDate = formatMinute . parse ( format . format ( right ) . concat ( " " ) . concat ( end ) ) ;
if ( right . before ( leftStandardStartDate ) ) {
} else if ( right . before ( standardEndDate ) ) {
costMin + = ( left . getTime ( ) - leftStandardStartDate . getTime ( ) ) / NumConstant . ONE_THOUSAND / NumConstant . SIXTY ;
} else {
costMin + = delta_T ;
}
}
if ( NumConstant . TWO = = list . size ( ) ) return costMin ;
for ( int index = NumConstant . ONE ; index < list . size ( ) - NumConstant . ONE ; index + + )
if ( StringUtils . equals ( ProjectConstant . DAY_TYPE_WORK , list . get ( index ) . getType ( ) ) )
costMin + = delta_T * NumConstant . SIXTY ;
return costMin ;
}
}
logger . warn ( "计算工作日,没有找到开始日期和结束日期,可能数据库中没有存储对应时段的数据,开始时间:{},结束时间:{}" , left , right ) ;
return null ;
}
private Integer getWorkDays ( Date start , Date end ) {
String startDateStr = DateUtils . format ( start , DateUtils . DATE_PATTERN_YYYYMMDD ) ;
String endDateStr = DateUtils . format ( end , DateUtils . DATE_PATTERN_YYYYMMDD ) ;
if ( startDateStr . equals ( endDateStr ) ) {
logger . info ( String . format ( "%s-%s起止时间一致,返回<1," , startDateStr , endDateStr ) ) ;
return 0 ;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat ( "yyyyMMdd" ) ;
try {
Date startDate = simpleDateFormat . parse ( startDateStr ) ;
Date endDate = simpleDateFormat . parse ( endDateStr ) ;
long day = ( endDate . getTime ( ) - startDate . getTime ( ) ) / ( 24 * 60 * 60 * 1000 ) ;
logger . info ( String . format ( "当前日期[%s]-被吹日期[%s]=%s" , endDateStr , startDateStr , day ) ) ;
List < CalenderEntity > list = calenderDao . selectByStartAndEnd ( startDateStr , endDateStr ) ;
long totalHoliday = 0 ;
for ( CalenderEntity calenderEntity : list ) {
if ( ! "1" . equals ( calenderEntity . getType ( ) ) ) {
totalHoliday + = 1 ;
}
}
logger . info ( String . format ( "期间的节假日[%s-%s]=%s" , endDateStr , startDateStr , totalHoliday ) ) ;
long detentionDay = day - totalHoliday ;
logger . info ( String . format ( "当前日期[%s]-被吹日期[%s]-期间的节假日[%s]=%s" , endDateStr , startDateStr , totalHoliday , detentionDay ) ) ;
return ( int ) detentionDay ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
return - 1 ;
}
private Integer getCalendarDays ( Date start , Date end ) {
String startDateStr = DateUtils . format ( start , DateUtils . DATE_PATTERN_YYYYMMDD ) ;
String endDateStr = DateUtils . format ( end , DateUtils . DATE_PATTERN_YYYYMMDD ) ;
if ( startDateStr . equals ( endDateStr ) ) {
logger . info ( String . format ( "%s-%s起止时间一致,返回<1," , startDateStr , endDateStr ) ) ;
return 0 ;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat ( "yyyyMMdd" ) ;
try {
Date startDate = simpleDateFormat . parse ( startDateStr ) ;
Date endDate = simpleDateFormat . parse ( endDateStr ) ;
long day = ( endDate . getTime ( ) - startDate . getTime ( ) ) / ( 24 * 60 * 60 * 1000 ) ;
return ( int ) day ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
return - 1 ;
}
}