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

Posted It-shuang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算两个日期之间的工作日(去掉周末和节假日)相关的知识,希望对你有一定的参考价值。

  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 sdate
116     * @return
117     */
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 sdate
139     * @return
140     */
141     private long validateEndTime(Calendar edate)
142     {
143         if(edate.get(Calendar.DAY_OF_WEEK) == 1)//结束日期是周日,如果结束日期是周六、周末自动修复为这周五18:00
144         {
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:00
152             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 sdate
164     * @param edate
165     * @return
166     */
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) != 1
171         && 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=52200000
182         // 获取结束时间的偏移量
183         long echarge = 0;
184         if (edate.get(Calendar.DAY_OF_WEEK) != 1
185         && 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 start
204     * -起始时间,共有3个重载方法,可以传入long型,Long型,与Date型
205     * @param end
206     * -结束时间,共有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 start
217     * @param end
218     * @return
219     */
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 mss
324          * @return
325          * <br><b>作者: @author zhushunagshuang</b>
326          * <br>创建时间:2016年7月21日 下午3:12:23
327          */
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          * @return
356          * @throws ParseException
357          * <br><b>作者: @author zhushunagshuang</b>
358          * <br>创建时间:2016年7月21日 下午5:12:08
359          */
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         

 

以上是关于计算两个日期之间的工作日(去掉周末和节假日)的主要内容,如果未能解决你的问题,请参考以下文章

周末及节假日天数去掉

如何计算两个日期之间的营业时间(R语言)?

oracle怎么计算两个日期之间去除周末的天数?

Java工作日计算工具类

日期选择器国定假日计数

java 给一个日期,往后加三天,如果是周末,节假日不算天数。直到加满三天为之,得出日期。