您的位置:首页 > 编程语言 > Java开发

工作时效计算逻辑与算法时效--对节假日、周末调班、周末时间进行处理

2013-12-06 14:27 393 查看
前几天项目中要开发一个计算时效的功能,在网上找了好久没有找到相关的代码,只要自己埋头苦干来设计它的逻辑和算法了。	时效也就是正常工作的时间。	项目是一个问题反馈相关的系统。对于一个问题反馈有上报时间和解决时间,这两个时间的差值即为解决这个问题的时效。当然如果紧紧是两者相减,也就不用这么大费周章了。它需要排除中午休息时间,下班时间、上班前时间、周末时间、节假日时间、节假日调班时间。	     现在来整理下时效计算应该考虑到的问题:     目的:计算出正确的时效。     计算方式:解决时间-上报时间。     处理:     1、对于上报时间处理:       (1) 上报时间在上午上班时间之前,将该时间推到当天上午上班时间(例如9:00),       (2) 上报时间在下午下班时间之后,将时间推到下一次上班时间(例如,周三下班时间上报,周四需要上班,那么将其推到周四9:00),对于周五下班后上报问题,需要推到下周一上班时间。(假设周末正常休息,周末调班的后面再说)。       (3)上报时间是在中午休息时间段(12:00-14:00),将时间推到下午上班时间(14:00)。       (4)周末时间上报,推到下一次上班时间。(需要考虑周末是否要上班,即为节假日调班时间)。       (5)正常周一到周五,但是属于节假日,将时间推到下一次正常上班时间。    2、对于解决时间处理:        (1)解决时间在上午上班时间之前,将时间推到上一次下班时间,(例如:周四上班前解决,周三正常上班,则解决时间应该为周三下班时间)。特别要注意的是周一,周一上班前解决的话,需要将时间推到上周五下班时间(假设周六周日正常休息)。         (2)解决时间在下午下班时间之后,将时间推到当天的下午下班时间。         (3)解决时间在中午休息时间段(12:00-14:00),将时间推到当天上午下班时间。         (4)周末解决时间,将时间推到上一次下午上班时间。(需要考虑周末是否要上班,即为解决日调班时间)         (5)正常周一到周五,但是属于节假日,将时间推到上一次下午下班时间。==========================================================================================
//计算时效
private long countAgeing(DateTime inputTime,DateTime closeTime) throws Exception{
//处理上报时间
inputTime = handleInputTime(inputTime);
//处理结束时间
closeTime = handleCloseTime(closeTime);
return countRealAgeing(inputTime,closeTime);
}
/**
* 实际计算时效的算法
* @param inputTime
* @param closeTime
* @return
* @throws Exception
*/
private long countRealAgeing(DateTime inputTime,DateTime closeTime) throws Exception{
int inputWeek = getWeekTime(inputTime); // 得到上报是间时星期几,1~7表示星期天到星期六
Calendar inputDateCalendar = Calendar.getInstance();
inputDateCalendar.setTime(new DateTime(inputTime,DateTime.YEAR_TO_DAY));
Calendar closeDateCalendar = Calendar.getInstance();
closeDateCalendar.setTime(new DateTime(closeTime,DateTime.YEAR_TO_DAY));
//====================假设这段时间内只是正常的上下班时间,忽略节假日时间==在后面重新将节假日计算进来 start===========
//===每一天节假日,则减一天的上班时间=========================
//===每一个周末调班,则加一天上班时间=========================

long day = 86400000;//一天的millis
long mod =(closeDateCalendar.getTimeInMillis()-inputDateCalendar.getTimeInMillis())/day; //总天数
System.out.println("----->天数:" +mod);
long weekNum = mod/7;
long cut = weekNum * 2; //两天周末
long yuShuDay = mod % 7; //剩余天数
if(inputWeek+yuShuDay>7){
cut +=2;
}
if(inputWeek+yuShuDay == 7){
cut ++;
}

//===================end===========================
inputDateCalendar.setTime(inputTime);

long inputTimeStartLong = inputDateCalendar.getTimeInMillis();
DateTime inputTempTime = new DateTime(inputTime,DateTime.YEAR_TO_DAY);
inputDateCalendar.setTime(new DateTime(inputTempTime.toString()+Const.AFTERMOON_END_WORK,DateTime.YEAR_TO_SECOND));
long inputTimeEndLong = inputDateCalendar.getTimeInMillis();

DateTime endTempTime = new DateTime(closeTime,DateTime.YEAR_TO_DAY);
closeDateCalendar.setTime(new DateTime(endTempTime.addHour(Const.MORNING_START_WORK),DateTime.YEAR_TO_SECOND));
long closeTimeStartLong = closeDateCalendar.getTimeInMillis();
closeDateCalendar.setTime(closeTime);
long closeTimeEndLong = closeDateCalendar.getTimeInMillis();
//long hour = 60*60*100;
long ageingLong = 0L;
//Long  middayNum = 2*60*60*1000L;
if(mod == 0){ //表示同一天

System.out.println(" inputTime: "+inputTime+" closeTime: "+closeTime);

inputDateCalendar.setTime(inputTime);
closeDateCalendar.setTime(closeTime);

if(inputTime.before(new DateTime(inputTempTime.addHour(Const.MORNING_END_WORK),DateTime.YEAR_TO_SECOND)) && closeTime.after(new DateTime(endTempTime.addHour(Const.AFTERMOON_START_WORK),DateTime.YEAR_TO_SECOND))){
//同一天跨中午
ageingLong = closeDateCalendar.getTimeInMillis() - inputDateCalendar.getTimeInMillis()-Const.SIESTA;
}else{

ageingLong = closeDateCalendar.getTimeInMillis() - inputDateCalendar.getTimeInMillis();
}

}else{//表示开始时间跟结束时间不在同一天

ageingLong= inputTimeEndLong-inputTimeStartLong+closeTimeEndLong - closeTimeStartLong + (mod - cut-1+countRestDay(inputTime, closeTime))*Const.WORK_TIME_LENGTH;
if(inputTime.before(new DateTime(inputTempTime.addHour(Const.MORNING_END_WORK),DateTime.YEAR_TO_SECOND))){
ageingLong -= Const.SIESTA;
}

if(closeTime.after(new DateTime(endTempTime.addHour(Const.AFTERMOON_START_WORK),DateTime.YEAR_TO_SECOND))){
ageingLong -= Const.SIESTA;
}
}
System.out.println("ageingLong:"+ageingLong);
if(ageingLong<0){
return 0;
}else{

return ageingLong;
}

}
/**
* 时间段内包含节假日和调班的日期
* 将它计算出来汇总。
* @param inputTime
* @param closeTime
* @return
* @throws Exception
*/
private int countRestDay(DateTime inputTime,DateTime closeTime) throws Exception{
DateTime inputNow = new DateTime(inputTime,DateTime.YEAR_TO_DAY);
DateTime closeNow = new DateTime(closeTime,DateTime.YEAR_TO_DAY);
inputNow = inputNow.addDay(1);
//传入null表示跨年的情况
List<PrpfeedbackfestivalDto> workDayList = findWorkByYear(null);
List<PrpfeedbackfestivalDto> festivalList = findFestivalByYear(null); //查找节假日
int index = 0;
while(inputNow.after(inputTime)&&inputNow.before(closeNow)){
for(PrpfeedbackfestivalDto festival:festivalList ){
int i=99;
i=inputNow.compareTo(festival.getHoliday());

if(i==0){
--index;
break;
}
}

for(PrpfeedbackfestivalDto workDay:workDayList){
int i=99;
i=inputNow.compareTo(workDay.getHoliday());

if(i==0){
++index;
break;
}
}

inputNow = inputNow.addDay(1);
}
return index;

}


处理上报时间和解决时间:
/**
* 处理结束时间
* @param closeTime
* @return
* @throws Exception
*/

private DateTime handleCloseTime(DateTime closeTime) throws Exception{
int closeWeek = getWeekTime(closeTime);
DateTime closeTempTime = new DateTime(closeTime, DateTime.YEAR_TO_DAY);

if(isWorkDay(closeTime)&&isFestival(closeTime)){ //正常工作时间    -----不包含节假日,周末正常休息-----
if(closeWeek == 7){//表示周六
//closeTime = new DateTime(closeTempTime.addDay(-1).toString()+Const.END_WORK_TIME,DateTime.YEAR_TO_SECOND);
closeTime = findHolidayBeforeLastDay(closeTime);
}else if(closeWeek == 1){//周日
//closeTime = new DateTime(closeTempTime.addDay(-2).toString()+Const.END_WORK_TIME,DateTime.YEAR_TO_SECOND);
closeTime = findHolidayBeforeLastDay(closeTime);
}else if(closeWeek == 2){ //周一
c681
上班时间前,将时间推到上星期五
if(isBeforeStartWork(closeTime)){//周一上班时间前
//closeTime = new DateTime(closeTempTime.addDay(-3).toString()+Const.END_WORK_TIME,DateTime.YEAR_TO_SECOND);
closeTime = findHolidayBeforeLastDay(closeTime);
}else if(isAfterEndWork(closeTime)){
closeTime = new DateTime(closeTempTime.toString()+Const.AFTERMOON_END_WORK,DateTime.YEAR_TO_SECOND);
}
}else{
if(isBeforeStartWork(closeTime)){
//closeTime = new DateTime(closeTempTime.addDay(-1).toString()+Const.END_WORK_TIME,DateTime.YEAR_TO_SECOND);
closeTime = findHolidayBeforeLastDay(closeTime);
}else if(isAfterEndWork(closeTime)){
closeTime = new DateTime(closeTempTime.toString()+Const.AFTERMOON_END_WORK,DateTime.YEAR_TO_SECOND);
}
}
}else if(!isFestival(closeTime)){//节假日时间,不用上班

closeTime = findHolidayBeforeLastDay(closeTime);

}else if(!isWorkDay(closeTime)){ //周末正常上班时间

if(isBeforeStartWork(closeTime)){//上班前节假的,则要找到这个放假前的下班时间

closeTime =findHolidayBeforeLastDay(closeTime);

}else if(isAfterEndWork(closeTime)){
closeTime = new DateTime(closeTempTime.toString()+Const.AFTERMOON_END_WORK,DateTime.YEAR_TO_SECOND);
}

}

if(closeTime.before(new DateTime(closeTempTime.addHour(Const.AFTERMOON_START_WORK),DateTime.YEAR_TO_SECOND))&&closeTime.after(new DateTime(closeTempTime.addHour(Const.MORNING_END_WORK),DateTime.YEAR_TO_SECOND))){
//中午时间
closeTime = new DateTime(closeTempTime.addHour(Const.MORNING_END_WORK),DateTime.YEAR_TO_SECOND);
}

return closeTime;
}

/**
* 处理上报时间
* @param inputTime
* @return
* @throws Exception
*/

private DateTime handleInputTime(DateTime inputTime) throws Exception{
//处理上报时间
int inputWeek = getWeekTime(inputTime);
DateTime inputTempTime = new DateTime(inputTime, DateTime.YEAR_TO_DAY);

if(isFestival(inputTime) && isWorkDay(inputTime)){ //输入的日期既不是节假日,也不是调班的周末,**属于正常时间**

if(inputWeek == 7){//表示是星期六,则要将时间设置为下个正常上班时间
//inputTime = new DateTime(inputTempTime.addDay(2).addHour(9),DateTime.YEAR_TO_SECOND);
inputTime = findHolidayAfterFirstWorkDay(inputTime);

}else if(inputWeek == 1){//表示星期天,则将时间设置成下个正常上班时间
//inputTime = new DateTime(inputTempTime.addDay(1).addHour(9),DateTime.YEAR_TO_SECOND);
inputTime = findHolidayAfterFirstWorkDay(inputTime);

}else if(inputWeek == 6){//表示是星期五发生的
if(isBeforeStartWork(inputTime)){
//如果是上班时间前上报的
inputTime = new DateTime(inputTempTime.addHour(Const.MORNING_START_WORK),DateTime.YEAR_TO_SECOND);
}else if(isAfterEndWork(inputTime)){
//如果是下班时间后,则要转移到到下个正常上班时间
//inputTime = new DateTime(inputTempTime.addDay(3).addHour(9),DateTime.YEAR_TO_SECOND);
inputTime = findHolidayAfterFirstWorkDay(inputTime);
}
}else{
if(isBeforeStartWork(inputTime)){
inputTime = new DateTime(inputTempTime.addHour(Const.MORNING_START_WORK),DateTime.YEAR_TO_SECOND);
}else if(isAfterEndWork(inputTime)){
//inputTime = new DateTime(inputTempTime.addDay(1).addHour(9),DateTime.YEAR_TO_SECOND);
inputTime = findHolidayAfterFirstWorkDay(inputTime);
}
}
}else if(!isFestival(inputTime)){//输入时间正好是节假日
//递归判断找到放假后的第一天上班日期
inputTime = findHolidayAfterFirstWorkDay(inputTime);

}else if(!isWorkDay(inputTime)){//输入的时间是周末,但是正好是调班日期,这一天需要上班

if(isBeforeStartWork(inputTime)){
inputTime = new DateTime(inputTempTime.addHour(Const.MORNING_START_WORK),DateTime.YEAR_TO_SECOND);
}else if(isAfterEndWork(inputTime)){

inputTime = findHolidayAfterFirstWorkDay(inputTime);
}

}

if(inputTime.before(new DateTime(inputTempTime.addHour(Const.AFTERMOON_START_WORK),DateTime.YEAR_TO_SECOND))&&inputTime.after(new DateTime(inputTempTime.addHour(Const.MORNING_END_WORK),DateTime.YEAR_TO_SECOND))){
//中午时间
inputTime = new DateTime(inputTempTime.addHour(Const.AFTERMOON_START_WORK),DateTime.YEAR_TO_SECOND);
}

return inputTime;
}
各个工具方法:
/**
* 找到放假后的第一天上班日期和时间(用于上班)
* @param dateTime
* @return
* @throws Exception
*/
private DateTime findHolidayAfterFirstWorkDay(DateTime dateTime) throws Exception{
boolean flag = true;
dateTime = dateTime.addDay(1);

while(flag){

if(!isFestival(dateTime)){
//当前日期是节假日
dateTime = dateTime.addDay(1);
}else{

//不是节假日
//判断是不是周末
if(!isWorkDay(dateTime) || (getWeekTime(dateTime)!=1 && getWeekTime(dateTime)!=7)){
//需要工作的周末,或者是非节假日的周一到周五
DateTime dateTempTime = new DateTime(dateTime,DateTime.YEAR_TO_DAY);
dateTime = new DateTime(dateTempTime.addHour(Const.MORNING_START_WORK),DateTime.YEAR_TO_SECOND);
flag = false; //找到正确时间,退出循环
}else{
dateTime = dateTime.addDay(1);
}
}

}

System.out.println(dateTime);
return dateTime;
}

/**
* 找到放假前最后一天的下班日期和时间(用于下班)
* @param dateTime
* @return
* @throws Exception
*/
private DateTime findHolidayBeforeLastDay(DateTime dateTime) throws Exception{
boolean flag = true;

dateTime = dateTime.addDay(-1);
while(flag){
if(!isFestival(dateTime)){ //判断是否为节假日,
//还是节假日
dateTime = dateTime.addDay(-1);
}else{
//不是节假日
//判断是不是周末,如果是周末并且需要加班,或者是正常的星期一到星期五
if(!isWorkDay(dateTime) || (getWeekTime(dateTime)!=1 && getWeekTime(dateTime)!=7)){
//需要工作的周末,或者是非节假日的周一到周五
DateTime dateTempTime = new DateTime(dateTime,DateTime.YEAR_TO_DAY);
dateTime = new DateTime(dateTempTime.toString()+Const.AFTERMOON_END_WORK,DateTime.YEAR_TO_SECOND);

flag = false; //得到正确时间,退出本次循环
}else{
dateTime = dateTime.addDay(-1);
}

}
}

return dateTime;
}

/**
* 是否节假日,如果是节假日,则返回false(不要上班),反之返回 true(要上班)。
* @param dateTime
* @return
* @throws Exception
*/
private boolean isFestival(DateTime dateTime) throws Exception{
List<PrpfeedbackfestivalDto> festivalList = findFestivalByYear(dateTime); //查找节假日
DateTime nowDay = new DateTime(dateTime,DateTime.YEAR_TO_DAY);
int isFestival = 99;
if(festivalList != null && festivalList.size()>0){

for(PrpfeedbackfestivalDto festival:festivalList){
isFestival = nowDay.compareTo(new DateTime(festival.getHoliday(),DateTime.YEAR_TO_DAY));
if(isFestival == 0){//如果为0的话,则表示当前日期就是节假日
break;
}
}

}

if(isFestival == 0){//如果为0的话,则表示当前日期就是节假日
return false;
}else{
return true;
}
}

/**
* 判断周末是否需要上班,如果要上班则返回false;不上班返回true
* @param dateTime
* @return
* @throws Exception
*/
private boolean isWorkDay(DateTime dateTime) throws Exception{
List<PrpfeedbackfestivalDto> workDayList = findWorkByYear(dateTime); //找到周末需要工作的时间
int isWorkDay = 99;
DateTime nowDay = new DateTime(dateTime,DateTime.YEAR_TO_DAY);
if(workDayList != null && workDayList.size()>0){

for(PrpfeedbackfestivalDto workDay:workDayList){
isWorkDay = nowDay.compareTo(workDay.getHoliday());
if(isWorkDay == 0){
break;
}
}

}

if(isWorkDay == 0){
return false; //周末时间,但是需要上班的时间
}else{
//周末时间,不需要上班
//表示这个时间没有在配置表中配置,属于正常时间
return true;
}
}

/**
* 判断时间是否在上班时间前
* @param dateTime
* @return
*/
private boolean isBeforeStartWork(DateTime dateTime){
DateTime tempTime = new DateTime(dateTime,DateTime.YEAR_TO_DAY);
DateTime startWork1 = new DateTime(tempTime,DateTime.YEAR_TO_SECOND); // 2013-11-05 00:00:00
DateTime startWork2 = new DateTime(tempTime.addHour(Const.MORNING_START_WORK),DateTime.YEAR_TO_SECOND); // 2013-11-05 09:00:00

if(dateTime.after(startWork1)&& dateTime.before(startWork2)){ // 表示发生在上班时间前
return true;
}

return false;
}
/**
* 判断时间是否在下班时间后
* @param dateTime
* @return
*/
private boolean isAfterEndWork(DateTime dateTime){
DateTime tempTime = new DateTime(dateTime,DateTime.YEAR_TO_DAY);
DateTime endWork1 = new DateTime(tempTime.toString()+Const.AFTERMOON_END_WORK,DateTime.YEAR_TO_SECOND);
DateTime endWork2 = new DateTime(tempTime.addDay(1),DateTime.YEAR_TO_SECOND);
if(dateTime.after(endWork1) && dateTime.before(endWork2)){ //表示下班时间段
return true;
}
return false;
}

/**
* 转换为星期几
* @param dateTime
* @return
*/

private int getWeekTime(DateTime dateTime){

Calendar calendar = Calendar.getInstance();
calendar.setTime(dateTime);
int week =calendar.get(Calendar.DAY_OF_WEEK);
//如果week 为 7时是周六,为1时是周日
System.out.println(week);
return week;
}

/**
* 得到节假日的时间
* @param dateTime
* @return
* @throws Exception
*/
private List<PrpfeedbackfestivalDto> findFestivalByYear(DateTime dateTime) throws Exception{

String conditions = "1=1";
//解决跨年的问题
if(dateTime != null && !dateTime.isEmpty()){
conditions += SqlUtils.convertString("year", dateTime.getYear()+"");
}
conditions += SqlUtils.convertString("iswork", "0");
List<PrpfeedbackfestivalDto> list = (List<PrpfeedbackfestivalDto>) blPrpfeedbackfestivalFacade.findByConditions(conditions);
return list;
}

/**
* 得到周六,周日需要工作的日期(也就是调休时间)
* @param dateTime
* @return
* @throws Exception
*/
private List<PrpfeedbackfestivalDto> findWorkByYear(DateTime dateTime) throws Exception{

String conditions = "1=1";
/**
* 用来解决跨年的问题
*/
if(dateTime != null && !dateTime.isEmpty()){
conditions += SqlUtils.convertString("year", dateTime.getYear()+"");
}
conditions += SqlUtils.convertString("iswork", "1");
List<PrpfeedbackfestivalDto> list = (List<PrpfeedbackfestivalDto>) blPrpfeedbackfestivalFacade.findByConditions(conditions);
return list;
}
    节假日和周末调休的时间是配置在数据库中,可以根据每年放假时间不同进行配置。
实体类:(PrpfeedbackfestivalDto.java),省了get/set方法
private static final long serialVersionUID = 1L;
/** 属性holiday 日期*/
private DateTime holiday = new DateTime();
/** 属性iswork 是否工作,1--需要工作,0--放假*/
private String iswork = "";
/** 属性year */
private String year = "";
//备注
private String remark;
常量类(Const.java)
public static int MORNING_START_WORK = 9; //上午开始上班时间
public static int MORNING_END_WORK = 12; //上午下班时间
public static int AFTERMOON_START_WORK = 14; //下午上班时间
public static String AFTERMOON_END_WORK = " 18:30:00";//下午上班时间
public static long WORK_TIME_LENGTH = 27000000;//工作
public static long HOUR = 3600000;
public static long SIESTA = 7200000; //中午休息两个小时

//读取时效的配置文件
static{

try {
InputStream in = new Const().getClass().getResourceAsStream("ageing.properties");
Properties properties = new Properties();
properties.load(in);
String morningStartWork = properties.getProperty("morningstartwork");
if(StringUtils.isNotEmpty(morningStartWork)){
MORNING_START_WORK = Integer.parseInt(morningStartWork.trim());
System.out.println("MORNING_START_WORK"+MORNING_START_WORK);
}
String morningEndWork = properties.getProperty("morningendwork");
if(StringUtils.isNotEmpty(morningEndWork)){
MORNING_END_WORK = Integer.parseInt(morningEndWork.trim());
System.out.println("MORNING_END_WORK"+MORNING_END_WORK);
}
String aftermoonStartWork = properties.getProperty("aftermoonstartwork");
if(StringUtils.isNotEmpty(aftermoonStartWork)){
AFTERMOON_START_WORK = Integer.parseInt(aftermoonStartWork.trim());
System.out.println("AFTERMOON_START_WORK"+AFTERMOON_START_WORK);
}
String aftermoonEndWork = properties.getProperty("aftermoonendwork");
if(StringUtils.isNotEmpty(aftermoonEndWork)){
AFTERMOON_END_WORK = " "+(aftermoonEndWork.trim());
System.out.println("AFTERMOON_END_WORK"+AFTERMOON_END_WORK);
}

String workTimeLengthHourStr = properties.getProperty("worktimelength");

if(StringUtils.isNotEmpty(workTimeLengthHourStr)){
Double workTimeLengthHour = Double.parseDouble(workTimeLengthHourStr);
WORK_TIME_LENGTH = (long) (workTimeLengthHour*HOUR);
System.out.println("WORK_TIME_LENGTH"+WORK_TIME_LENGTH);
}

String siestaStr = properties.getProperty("siesta");
if(StringUtils.isNotEmpty(siestaStr)){
SIESTA = Integer.parseInt(siestaStr.trim())*HOUR;
}

} catch (IOException e) {
e.printStackTrace();
}
}
属性文件:ageing.properties
morningstartwork=9
morningendwork=12
aftermoonstartwork=14
aftermoonendwork=18:30:00
worktimelength=7.5
siesta=2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐