工作时效计算逻辑与算法时效--对节假日、周末调班、周末时间进行处理
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)正常周一到周五,但是属于节假日,将时间推到上一次下午下班时间。==========================================================================================
处理上报时间和解决时间:
实体类:(PrpfeedbackfestivalDto.java),省了get/set方法
//计算时效 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
相关文章推荐
- 输入开始时间和工作天数,计算结束时间,需考虑节假日周末和调休
- 输入【开始时间】和【结束时间】,计算工作天数,需考虑节假日周末和调休
- hihocoder #1068 : RMQ-ST算法 ( RMQ算法 O(nlogn)处理 O(1)查询 *【模板】 1)初始化d数组直接读入+计算k值用数学函数log2()==*节约时间 )
- 在线Word编辑的jQuery插件时间:2010-12-29 09:15点击:122 次 【大 中 小】 在做OA或者工作流程的网站中,常常能够看到一些在线Word编辑进行文档处理的功能,这里我开发了
- 一道看上去很吓人的算法面试题:如何对n个数进行排序,要求时间复杂度O(n),空间复杂度O(1)
- 根据指定两个日期计算出这些时间内有多少天是周末 php程序函数代码
- 计算两个日期相差的工作天数,过滤了周末双休天数
- 11如何精确计算出一个算法的CPU运行时间?
- 一道看上去很吓人的算法面试题:如何对n个数进行排序,要求时间复杂度O(n),空间复杂度O(1)
- 算法的时间复杂度计算
- java String转bigdecimal 精确两位小数点然后对转的数进行算法计算。
- 使用console进行 性能测试 和 计算代码运行时间
- 利用GSON对json数据中的时间类型字符串进行处理,并且进行数据库查询
- [日志处理工作之四]从flume采集的event中提取能被kibana识别的时间戳 and 对比flume与logstash
- 单缓冲 vs 双缓冲 处理数据时间计算方法
- 计算日落日出时间算法与代码
- 运用Javascript实现时间重置、进行时间加减计算
- 算法时间维度的计算
- 计算一段程序进行的时间、 控制台下用Win32 API打开文件对话框
- (五)用swift4写iOS微信跳一跳的自动跳(开挂)程序——计算按压时间,基于WebDriverAgent进行模拟触屏