你的位置:首页 > Java教程

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


 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