首页 > 代码库 > 计算两个日期之间的工作日(去掉周末和节假日)

计算两个日期之间的工作日(去掉周末和节假日)

  1 package com.utouu.uphone.commons;  2   3 import java.text.ParseException;  4 import java.text.SimpleDateFormat;  5 import java.util.ArrayList;  6 import java.util.Calendar;  7 import java.util.Date;  8 import java.util.Iterator;  9 import java.util.List; 10  11 import org.springframework.stereotype.Component; 12 /** 13  * 获取工作日 14  * <br>创建日期:2016年7月21日 15  * <br><b>Copyright 2016 UTOUU All Rights Reserved</b> 16  * @author zhushuangshuang 17  * @since 1.0 18  * @version 1.0 19  */ 20 @Component 21 public class GetWorkDay { 22     /** 23     * 获取两个时间之内的工作日时间(只去掉两个日期之间的周末时间,法定节假日未去掉) 24     * 25     * @param start 26     * -起始时间,共有3个重载方法,可以传入long型,Long型,与Date型 27     * @param end 28     * -结束时间,共有3个重载方法,可以传入long型,Long型,与Date型 29     * @return Long型时间差对象 30     */ 31     /*public static void main(String[] args) { 32         GetWorkDay g=new GetWorkDay(); 33         List<Date> initHoliday; 34         try { 35             initHoliday = g.initHoliday(); 36             double days = g.getWorkdayTimeInMillisExcWeekendHolidays("2016-06-30 17-12-53","2016-08-30 11-27-50","yyyy-MM-dd HH-mm-ss",initHoliday); 37             double formateToDay = g.formateToDay(days); 38             String formatDuring = g.formatDuring(days); 39              System.out.println(formateToDay); 40             System.out.println(formatDuring); 41         } catch (ParseException e) { 42             // TODO Auto-generated catch block 43             e.printStackTrace(); 44         } 45     } */ 46      47     private double getWorkdayTimeInMillis(long start, long end, 48         List<Date> listHolidays) { 49      50         // 如果起始时间大于结束时间,将二者交换 51         if (start > end) { 52             long temp = start; 53             start = end; 54             end = temp; 55         } 56         // 根据参数获取起始时间与结束时间的日历类型对象 57         Calendar sdate = Calendar.getInstance(); 58         Calendar edate = Calendar.getInstance(); 59      60         sdate.setTimeInMillis(start); 61         edate.setTimeInMillis(end); 62      63         // 计算指定时间段内法定节假日天数的毫秒数 64         long holidays = 0; 65         if (listHolidays != null) { 66             holidays = getHolidaysInMillis(start, end, listHolidays); 67             listHolidays.clear(); 68         } 69      70         // 如果两个时间在同一周并且都不是周末日期,则直接返回时间差,增加执行效率 71         if ((sdate.get(Calendar.YEAR) == edate.get(Calendar.YEAR)) 72         && (sdate.get(Calendar.WEEK_OF_YEAR) == edate 73         .get(Calendar.WEEK_OF_YEAR)) 74         && (sdate.get(Calendar.DAY_OF_WEEK) != 1 && sdate 75         .get(Calendar.DAY_OF_WEEK) != 7) 76         && (edate.get(Calendar.DAY_OF_WEEK) != 1 && edate 77         .get(Calendar.DAY_OF_WEEK) != 7)) { 78         return new Long(end - start - holidays); 79         } 80         // 如果两个时间在同一周并且都是周末日期,则直接返回0 81         if ((sdate.get(Calendar.YEAR) == edate.get(Calendar.YEAR)) 82         && (sdate.get(Calendar.WEEK_OF_YEAR) == edate 83         .get(Calendar.WEEK_OF_YEAR)-1) 84         && (sdate.get(Calendar.DAY_OF_WEEK) == 1 85         || sdate.get(Calendar.DAY_OF_WEEK) == 7) 86         && 87         (edate.get(Calendar.DAY_OF_WEEK) == 1 88         || edate.get(Calendar.DAY_OF_WEEK) == 7)) { 89         start=validateStartTime(sdate); 90         end=validateEndTime(edate); 91         long result=end - start - holidays; 92         return new Long(result>0?result:0); 93         } 94      95         start=validateStartTime(sdate); 96         end=validateEndTime(edate); 97      98         // 首先取得起始日期与结束日期的下个周一的日期 99         Calendar snextM = getNextMonday(sdate);100         Calendar enextM = getNextMonday(edate);101     102         // 获取这两个周一之间的实际天数103         int days = getDaysBetween(snextM, enextM);104     105         // 获取这两个周一之间的工作日数(两个周一之间的天数肯定能被7整除,并且工作日数量占其中的5/7)106         int workdays = days / 7 * 5;107     108         // 计算最终结果,具体为:workdays加上开始时间的时间偏移量,减去结束时间的时间偏移量109         double a=(double)workdays*24*3600000;110         double result = (a + calcWorkdayTimeInMillis(sdate, edate, start, end) - holidays);111        return result > 0 ? result : 0;112     }113     /***114     * 验证开始日期是否合法,如果不合法,并返回修复后的正确日期毫秒数115     * @param sdate116     * @return117     */118     private long validateStartTime(Calendar sdate){119         if(sdate.get(Calendar.DAY_OF_WEEK) == 1)//开始日期从周日开始,如果开始时间为周末,自动修复为下周的9:00开始120         {121             sdate.add(Calendar.DATE,1);122             sdate.setTimeInMillis(sdate.getTime().getTime()- //从9点开始123             (((sdate.get(Calendar.HOUR_OF_DAY)-9) * 3600000)+ (sdate.get(Calendar.MINUTE) * 60000)+ (sdate.get(Calendar.SECOND) * 1000)));124         }else if(sdate.get(Calendar.DAY_OF_WEEK) == 7){//开始日期从周六开始125                 sdate.add(Calendar.DATE,2);126                 sdate.setTimeInMillis(127                 sdate.getTime().getTime()- //从9点开始,如果开始时间为周末,自动修复为下周的9:00开始128                 (((sdate.get(Calendar.HOUR_OF_DAY)-9) * 3600000)129                + (sdate.get(Calendar.MINUTE) * 60000)130                + (sdate.get(Calendar.SECOND) * 1000)));131         }132             return sdate.getTimeInMillis();133     }134 135 136     /***137     * 验证结束日期是否合法,如果不合法,并返回修复后的正确日期毫秒数138     * @param sdate139     * @return140     */141     private long validateEndTime(Calendar edate)142     {143         if(edate.get(Calendar.DAY_OF_WEEK) == 1)//结束日期是周日,如果结束日期是周六、周末自动修复为这周五18:00144         {145         edate.add(Calendar.DATE,-2);146         edate.setTimeInMillis(147         edate.getTime().getTime()+148         (18*3600000-((edate.get(Calendar.HOUR_OF_DAY) * 3600000)149         + (edate.get(Calendar.MINUTE) * 60000)150         + (edate.get(Calendar.SECOND) * 1000))));151         }else if(edate.get(Calendar.DAY_OF_WEEK) == 7){//结束日期是周六,如果结束日期是周六、周末自动修复为这周五18:00152             edate.add(Calendar.DATE,-1);153             edate.setTimeInMillis(154             edate.getTime().getTime()+155         (18*3600000-((edate.get(Calendar.HOUR_OF_DAY) * 3600000)156         + (edate.get(Calendar.MINUTE) * 60000)157         + (edate.get(Calendar.SECOND) * 1000))));}158         return edate.getTimeInMillis();159     }160     /***161     * 计算两个日期间的工作日天数,除周六日162     *163     * @param sdate164     * @param edate165     * @return166     */167     private long calcWorkdayTimeInMillis(Calendar sdate, Calendar edate,long start, long end) {168         // 获取开始时间的偏移量169         long scharge = 0;170         if (sdate.get(Calendar.DAY_OF_WEEK) != 1171         && sdate.get(Calendar.DAY_OF_WEEK) != 7) {172         // 只有在开始时间为非周末的时候才计算偏移量173         scharge += (sdate.get(Calendar.HOUR_OF_DAY) * 3600000);174         scharge += (sdate.get(Calendar.MINUTE) * 60000);175         scharge += (sdate.get(Calendar.SECOND) * 1000);176         scharge = ((24 * 3600000) - scharge);177     178         scharge += ((sdate.getTime().getTime() - start) - (3 * 24 * 3600000));179         }180         // (24*3600000=86400000)-((9*3600000+1800000)=34200000)+(3*24*3600000=259200000)-(2*24*3600000)=181         // 86400000-34200000=52200000182         // 获取结束时间的偏移量183         long echarge = 0;184         if (edate.get(Calendar.DAY_OF_WEEK) != 1185         && edate.get(Calendar.DAY_OF_WEEK) != (7)) {186         // 只有在结束时间为非周末的时候才计算偏移量187         echarge += (edate.get(Calendar.HOUR_OF_DAY) * 3600000);188         echarge += (edate.get(Calendar.MINUTE) * 60000);189         echarge += (edate.get(Calendar.SECOND) * 1000);190         echarge = ((24 * 3600000) - echarge);191         echarge += (edate.getTime().getTime() - end) - (24 * 3600000);192         echarge -= (2 * 24 * 3600000);193         }194         // (24*3600000=86400000)-(18*3600000=64800000)+(24*3=259200000)195         if (scharge < 0 || echarge < 0)196         scharge = echarge = 0;197         return scharge - echarge;198     }199     200     /**201     * 获取两个时间之内的工作日时间(只去掉两个日期之间的周末时间,法定节假日未去掉)202     *203     * @param start204     * -起始时间,共有3个重载方法,可以传入long型,Long型,与Date型205     * @param end206     * -结束时间,共有3个重载方法,可以传入long型,Long型,与Date型207     * @return Long型时间差对象208     */209     public double getWorkdayTimeInMillisExcWeekend(long start, long end) {210         return getWorkdayTimeInMillis(start, end);211     }212 213     /***214     * 获取两个时间之内的工作日时间(去掉两个日期之间的周末时间,法定节假日时间)215     *216     * @param start217     * @param end218     * @return219     */220     public double getWorkdayTimeInMillisExcWeekendHolidays(String start,String end, String format, List<Date> listHolidays) {221         SimpleDateFormat sdf = new SimpleDateFormat(format);222         Date sdate;223         Date edate;224         try {225             sdate = sdf.parse(start);226             edate = sdf.parse(end);227             return getWorkdayTimeInMillis(sdate.getTime(), edate.getTime(),228             listHolidays);229             } catch (ParseException e) {230             e.printStackTrace();231             return new Long(0);232         }233     }234     235     public double getWorkdayTimeInMillis(Long start, Long end) {236         return getWorkdayTimeInMillis(start.longValue(), end.longValue(), null);237         }238 239         public double getWorkdayTimeInMillis(Date start, Date end) {240         return getWorkdayTimeInMillis(start.getTime(), end.getTime(), null);241         }242 243         public double getWorkdayTimeInMillis(String start, String end, String format) {244             SimpleDateFormat sdf = new SimpleDateFormat(format);245             Date sdate;246             Date edate;247             try {248                 sdate = sdf.parse(start);249                 edate = sdf.parse(end);250                 return getWorkdayTimeInMillis(sdate, edate);251             } catch (ParseException e) {252                 e.printStackTrace();253                 return new Long(0);254             }255             }256     257             private long getHolidaysInMillis(long start, long end,258                 List<Date> listHolidays) {259                 Calendar scalendar = Calendar.getInstance();260                 Calendar ecalendar = Calendar.getInstance();261                 int daysofH = 0;262                 try {263         264                 scalendar.setTimeInMillis(start);265                 ecalendar.setTimeInMillis(end);266         267                 if (listHolidays == null)268                 return new Long(0);269                 Iterator<Date> iterator = listHolidays.iterator();270                 while (iterator.hasNext()) {271                 Calendar ca = Calendar.getInstance();272                 Date hdate = iterator.next();273                 ca.setTime(hdate);274                 if (ca.after(scalendar) && ca.before(ecalendar)) {275                     daysofH = daysofH + 1;276                 } else if (ca.getTimeInMillis() == scalendar.getTimeInMillis()) {277                     daysofH = daysofH + 1;278                 } else if (ca.getTimeInMillis() == ecalendar.getTimeInMillis()) {279                     daysofH = daysofH + 1;280                 }281                 }282         283                 } catch (Exception e) {284                     e.printStackTrace();285                     return new Long(0);286                 }287                    return daysofH * 24 * 3600000;288          }289         290         291         private Calendar getNextMonday(Calendar cal) {292                 int addnum = 9 - cal.get(Calendar.DAY_OF_WEEK);293                 if (addnum == 8)294                 addnum = 1;// 周日的情况295                 cal.add(Calendar.DATE, addnum);296                 return cal;297         }298 299             /**300             *301             * @param mss 302             * @param 要转换的毫秒数303             * @return 该毫秒数转换为 * days * hours * minutes * seconds 后的格式304             */305         public String formatDuring(double mss) {306             long days = (long) (mss / (1000 * 60 * 60 * 24));307             long hours = (long) ((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));308             long minutes = (long) ((mss % (1000 * 60 * 60)) / (1000 * 60));309             long seconds = (long) ((mss % (1000 * 60)) / 1000);310             return days + " days " + hours + " hours " + minutes + " minutes "311             + seconds + " seconds ";312             }313             314             /**315             * 获取两个日期之间的实际天数,支持跨年316             * @param start 317             * @param end 318             *  319             */320         /**321          * 获得两个日期之间的工作日322          * @since 1.0 323          * @param mss324          * @return325          * <br><b>作者: @author zhushunagshuang</b>326          * <br>创建时间:2016年7月21日 下午3:12:23327          */328         public double formateToDay(double mss){329             double days = mss / (1000 * 60 * 60 * 24);330             return days;331         }332         333         public int getDaysBetween(Calendar start, Calendar end) {334             if (start.after(end)) {335             Calendar swap = start;336             start = end;337             end = swap;338             }339 340             int days = end.get(Calendar.DAY_OF_YEAR)- start.get(Calendar.DAY_OF_YEAR);341             int y2 = end.get(Calendar.YEAR);342             if (start.get(Calendar.YEAR) != y2) {343                 start = (Calendar) start.clone();344                 do {345                     days += start.getActualMaximum(Calendar.DAY_OF_YEAR);346                     start.add(Calendar.YEAR, 1);347                 } while (start.get(Calendar.YEAR) != y2);348                 349             }350             return days;351         }352         /**353          * 手动维护2016年的节假日354          * @since 1.0 355          * @return356          * @throws ParseException357          * <br><b>作者: @author zhushunagshuang</b>358          * <br>创建时间:2016年7月21日 下午5:12:08359          */360         public List<Date> initHoliday() throws ParseException{                361             List<Date> holidays = new ArrayList<Date>();362             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");363             //元旦364             holidays.add(sdf.parse("2016-01-01"));365             holidays.add(sdf.parse("2016-01-02"));366             holidays.add(sdf.parse("2016-01-03"));367             //春节368             holidays.add(sdf.parse("2016-02-07"));369             holidays.add(sdf.parse("2016-02-08"));370             holidays.add(sdf.parse("2016-02-09"));371             holidays.add(sdf.parse("2016-02-10"));372             holidays.add(sdf.parse("2016-02-11"));373             holidays.add(sdf.parse("2016-02-12"));374             holidays.add(sdf.parse("2016-02-13"));375             //清明节376             holidays.add(sdf.parse("2016-04-02"));377             holidays.add(sdf.parse("2016-04-03"));378             holidays.add(sdf.parse("2016-04-04"));379             //劳动节380             holidays.add(sdf.parse("2016-04-30"));381             holidays.add(sdf.parse("2016-05-01"));382             holidays.add(sdf.parse("2016-05-02"));383             //端午节384             holidays.add(sdf.parse("2016-06-09"));385             holidays.add(sdf.parse("2016-06-10"));386             holidays.add(sdf.parse("2016-06-11"));387             //中秋节388             holidays.add(sdf.parse("2016-09-15"));389             holidays.add(sdf.parse("2016-09-16"));390             holidays.add(sdf.parse("2016-09-17"));391             //国庆节392             holidays.add(sdf.parse("2016-10-01"));393             holidays.add(sdf.parse("2016-10-02"));394             holidays.add(sdf.parse("2016-10-03"));395             holidays.add(sdf.parse("2016-10-04"));396             holidays.add(sdf.parse("2016-10-05"));397             holidays.add(sdf.parse("2016-10-06"));398             holidays.add(sdf.parse("2016-10-07"));399             return holidays;400         }401         402 }403         

 

计算两个日期之间的工作日(去掉周末和节假日)