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