因为业务需求,要对请假时间进行计算,也就是用户选定一个开始时间,在选定一个结束时间,你要给用户展示一个他请假的时长,这个时长肯定是除开节假日,双休,其中考虑到放假后的调休,中午午休,以及用户提交请假所处的时间段。
翻了翻网上的一些带佬的代码(毕竟码农的精华就在CV嘛),恩,有重合部分,但无法完全满足业务需求,所以还是需要自己动手做部分整合,最关键是部分代码需要调用外部接口,也把整合的代码放出。
第一个工具类:
package com.api.leave.utils;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* 请假计算(小时)
* 1.除去 节假日
* 2.除去 其他规定的 非工作时间(有具体的 实行者指定)
* 3.考虑一点 其他不上班时间 有些公司的特别
* @author fengjing
*
*/
public class HolidayDateUtil {
/**
* 节假日查询接口
* 使用方法 url+yyyyMMdd
*/
//时间格式化
public final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public final static SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd");
/**
* 从公认网站上获取 节假日信息
* @param url 获取节假日的 公认网站 url="网站地址"+时间 时间格式yyyyMMdd
* @param url
* @return 工作日对应结果为 0, 休息日对应结果为 1, 节假日对应的结果为 2, 网站失效-1, 数据格式改变-2
*/
public static String getHoliday(String date) {
ChineseCalendarUtils cc = new ChineseCalendarUtils();
try {
return cc.checkDate(date);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 判断某年某月有多少天
* @param year 年 "yyyy"
* @param moun 月 "m"
* @return
*/
public static int daysMonth(int year,int moun){
switch(moun){
case 0: return 31;
case 1: return ((year%4==0&&year%100!=0)||year%400==0)?29:28;
case 2: return 31;
case 3: return 30;
case 4: return 31;
case 5: return 30;
case 6: return 31;
case 7: return 31;
case 8: return 30;
case 9: return 31;
case 10: return 30;
case 11: return 31;
default: return 0;
}
}
/**
* 通过时间秒毫秒数判断两个时间的间隔
* @param tiny 开始时间
* @param large结束时间
* @return 返回几天
*/
public static int differentDaysByMillisecond(Date tiny,Date large){
if(format1.format(tiny).equals(format1.format(large))){
return 0;
}
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTime(tiny);
c2.setTime(large);
int result = c2.get(Calendar.DAY_OF_YEAR) - c1.get(Calendar.DAY_OF_YEAR);
/*Double why = Double.valueOf((large.getTime() - tiny.getTime()))/(1000*3600*24);
double d = Math.ceil(why);*/
return result;
}
/**
* 通过时间秒毫秒数判断两个时间的间隔
* @param tiny 开始时间
* @param large结束时间
* @return 返回几小时
*/
public static double differentHoursByMillisecond(Date tiny,Date large){
double hours = ((double) ((large.getTime() - tiny.getTime())) / (1000*3600));
return hours;
}
/**
* 时间格式yyyy-MM-dd HH:mm:ss
* @param start 请假开始时间 yyyy-MM-dd HH:mm:ss
* @param end 请假结束时间 yyyy-MM-dd HH:mm:ss
* @param startM 上班早晨开始时间 HH:mm:ss
* @param endE 上班早晨结束时间 HH:mm:ss
* @param startAf 上班下午开始时间 HH:mm:ss
* @param endAf 上班下午结束时间 HH:mm:ss
* @return
*/
public double calculateTimeHour(String start,String end,String startM,String endE,String startAf,String endAf){
if(start!=null&&end!=null&&startM!=null&&endE!=null&&startAf!=null&&endAf!=null){//确保时间格式正确和值存在
try {
Date dataStart = HolidayDateUtil.format.parse(start);
Date dataEnd = HolidayDateUtil.format.parse(end);
double hours = 0;
int monthDays = -1;
int yearTime = dataStart.getYear()+1900;
int mounthTime = dataStart.getMonth();
int dataTime = dataStart.getDate();
double lunchBreak;
int interval = HolidayDateUtil.differentDaysByMillisecond(dataStart,dataEnd);
//判断这年这月有多少天
monthDays = HolidayDateUtil.daysMonth(yearTime,mounthTime);
//第一天请假开始时间
String startday = start.substring(start.lastIndexOf(" ")+1,start.length()-1);
//最后一天请假结束时间
String endday = end.substring(end.lastIndexOf(" ")+1,end.length()-1);
double totalDay = 0;//累积总共请假多少天
for(int i=0;i<=interval;i++){
if(interval==0){//间隔0天 也就是 请假在一天之内
if(!"0".equals(HolidayDateUtil.getHoliday(yearTime+"-"+(((mounthTime+1))>=10?(mounthTime+1):"0"+(mounthTime+1))+"-"+(dataTime>10?dataTime:"0"+dataTime)))){
System.out.println(""+yearTime+(((mounthTime+1))>10?(mounthTime+1):"0"+(mounthTime+1))+(dataTime>10?dataTime:"0"+dataTime)+"非工作日期不需要计算");
return 0;
}
String s = start.substring(0,10)+" "+endE;
String s1 = start.substring(0,10)+" "+startAf;
String s2 = start.substring(0,10)+" "+startM;
String s3 = start.substring(0,10)+" "+endAf;
Date dataMorning = HolidayDateUtil.format.parse(s2);
Date dataAfternoon = HolidayDateUtil.format.parse(s3);
Date dataCenter1 = HolidayDateUtil.format.parse(s);
Date dataCenter2 = HolidayDateUtil.format.parse(s1);
//开始时间在9点前 结束时间:①9点前 ②9点到12点 ③12点到1点 ④1点到6点 ⑤6点后
if(dataStart.compareTo(dataMorning) <= 0){
if(dataEnd.compareTo(dataMorning) <= 0){
hours = 0;
lunchBreak = 0;
}else if(dataEnd.compareTo(dataMorning) > 0 && dataEnd.compareTo(dataCenter1) <= 0){
hours = differentHoursByMillisecond(dataMorning,dataEnd);
lunchBreak = 0;
}else if(dataEnd.compareTo(dataCenter1) > 0 && dataEnd.compareTo(dataCenter2) <= 0){
hours = differentHoursByMillisecond(dataMorning,dataCenter1);
lunchBreak = 0;
}else if(dataEnd.compareTo(dataCenter2) > 0 && dataEnd.compareTo(dataAfternoon) <= 0){
hours = differentHoursByMillisecond(dataMorning,dataEnd);
lunchBreak = 1;
}else{
hours = 8;
lunchBreak = 0;
}
}
//开始时间在9点到12点 结束时间:②9点到12点 ③12点到1点 ④1点到6点 ⑤6点后
else if(dataStart.compareTo(dataMorning) > 0 && dataStart.compareTo(dataCenter1) <= 0){
if(dataEnd.compareTo(dataMorning) > 0 && dataEnd.compareTo(dataCenter1) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = 0;
}else if(dataEnd.compareTo(dataCenter1) > 0 && dataEnd.compareTo(dataCenter2) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = differentHoursByMillisecond(dataCenter1,dataEnd);
}else if(dataEnd.compareTo(dataCenter2) > 0 && dataEnd.compareTo(dataAfternoon) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = 1;
}else{
hours = differentHoursByMillisecond(dataStart,dataAfternoon);
lunchBreak = 1;
}
}
//开始时间在12点到1点 结束时间:③12点到1点 ④1点到6点 ⑤6点后
else if(dataStart.compareTo(dataCenter1) > 0 && (dataStart.compareTo(dataCenter2)) <= 0){
if(dataEnd.compareTo(dataCenter1) > 0 && dataEnd.compareTo(dataCenter2) <= 0){
hours = 0;
lunchBreak = 0;
}else if(dataEnd.compareTo(dataCenter2) > 0 && dataEnd.compareTo(dataAfternoon) <= 0){
hours = differentHoursByMillisecond(dataCenter2,dataEnd);
lunchBreak = 0;
}else{
hours = differentHoursByMillisecond(dataStart,dataAfternoon);
lunchBreak = differentHoursByMillisecond(dataStart,dataCenter2);
}
}
//开始时间在1点到6点 结束时间: ④1点到6点 ⑤6点后
else if(dataStart.compareTo(dataCenter2) >0 && dataStart.compareTo(dataAfternoon) <= 0){
if(dataEnd.compareTo(dataCenter2) > 0 && dataEnd.compareTo(dataAfternoon) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = 0;
}else{
hours = differentHoursByMillisecond(dataStart,dataAfternoon);
lunchBreak = 0;
}
}
//开始时间在6点后
else{
hours = 0;
lunchBreak = 0;
}
}else{//间隔超过一天
dataTime +=(i==0?0:1);
if(dataTime>monthDays){
mounthTime ++;
dataTime=1;
if(mounthTime>11){
yearTime++;
mounthTime=0;
dataTime=1;
}
monthDays = HolidayDateUtil.daysMonth(yearTime,mounthTime);
}
//判断是否是节假日
if(!"0".equals(HolidayDateUtil.getHoliday(yearTime+"-"+(((mounthTime+1))>=10?(mounthTime+1):"0"+(mounthTime+1))+"-"+(dataTime>10?dataTime:"0"+dataTime)))){
System.out.println(""+yearTime+(((mounthTime+1))>10?(mounthTime+1):"0"+(mounthTime+1))+(dataTime>10?dataTime:"0"+dataTime)+"非工作日期不需要计算");
continue;
}
String s1 = yearTime+"-"+(((mounthTime+1))>=10?(mounthTime+1):"0"+(mounthTime+1))+"-"+(dataTime>=10?dataTime:"0"+dataTime)+" "+(i==0?startday:startM);
String s2 = yearTime+"-"+(((mounthTime+1))>=10?(mounthTime+1):"0"+(mounthTime+1))+"-"+(dataTime>=10?dataTime:"0"+dataTime)+" "+(i==interval?endday:endAf);
Date dateMorning = HolidayDateUtil.format.parse(s1.substring(0,10)+" "+startM);
Date dateAfternoon = HolidayDateUtil.format.parse(s1.substring(0,10)+" "+endAf);
Date dateCenter1 = HolidayDateUtil.format.parse(s1.substring(0,10)+" "+endE);
Date dateCenter2 = HolidayDateUtil.format.parse(s1.substring(0,10)+" "+startAf);
dataStart = HolidayDateUtil.format.parse(s1);
dataEnd = HolidayDateUtil.format.parse(s2);
//第一天 dataEnd为6点 判断开始时间 ①9点前 ②9点到12点 ③12点到1点 ④ 1点到6点 ⑤ 6点之后
if(i == 0){
if(dataStart.compareTo(dateMorning) <= 0){
hours = 8;
lunchBreak = 0;
}else if(dataStart .compareTo(dateMorning) > 0 && dataStart.compareTo(dateCenter1) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = 1;
}else if(dataStart.compareTo(dateCenter1) > 0 && dataStart.compareTo(dateCenter2) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = differentHoursByMillisecond(dateCenter1,dataStart);
}else if(dataStart.compareTo(dateCenter2) > 0 && dataStart.compareTo(dateAfternoon) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = 0;
}else{
hours = 0;
lunchBreak = 0;
}
//中间天 hours 为8 lunchBreak为0
}else if( i != 0 && i != interval){
hours = 8;
lunchBreak = 0;
//最后一天 dataStart为9点 判断结束时间 ①9点前 ②9点到12点 ③12点到1点 ④ 1点到6点 ⑤ 6点之后
}else{
if(dataEnd.compareTo(dateMorning) <= 0){
hours = 0;
lunchBreak = 0;
}else if(dataEnd .compareTo(dateMorning) > 0 && dataEnd.compareTo(dateCenter1) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = 0;
}else if(dataEnd.compareTo(dateCenter1) > 0 && dataEnd.compareTo(dateCenter2) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = differentHoursByMillisecond(dateCenter1,dataEnd);
}else if(dataEnd.compareTo(dateCenter2) > 0 && dataEnd.compareTo(dateAfternoon) <= 0){
hours = differentHoursByMillisecond(dataStart,dataEnd);
lunchBreak = 1;
}else{
hours = 8;
lunchBreak = 0;
}
}
}
System.out.println(yearTime+"-"+(((mounthTime+1))>10?(mounthTime+1):"0"+(mounthTime+1))+"-"+(dataTime>10?dataTime:"0"+dataTime)+" 请假:"+(hours-lunchBreak)+"小时");
totalDay+=hours-lunchBreak;
}
System.out.println(totalDay);
return totalDay;
} catch (ParseException e) {
e.printStackTrace();
}
}
return -1;
}
/**
* 累积请假共多少天
* @param totalDay
* @return totalDay < 24小时按小时算 totalDay >= 24小时按天算
*/
public String totalDay(double totalDay){
if(totalDay > 24){
return (totalDay/24) + "天";
}else{
return totalDay + "小时";
}
}
public static void main(String args[]) throws IOException{
HolidayDateUtil qj= new HolidayDateUtil();
//测试
qj.calculateTimeHour("2019-9-01 09:00:00","2019-10-09 12:00:00","09:00:00","12:00:00","13:00:00","18:00:00");
}
}
第二个工具类:
package com.api.leave.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* @author qyw
* @description 日期日历工具类
* @date Created in 21:01 2019/1/31
**/
public class ChineseCalendarUtils {
// 法律规定的放假日期
private List<String> lawHolidays = Arrays.asList("2019-9-13", "2019-9-14",
"2019-09-15", "2019-10-01", "2019-10-02", "2019-10-03", "2019-10-04",
"2019-10-05", "2019-10-06", "2019-10-07");
// 由于放假需要额外工作的周末
private List<String> extraWorkdays = Arrays.asList(
"2019-09-16", "2019-09-29", "2019-10-12", "2019-10-08");
/**
* @author qyw
* @description 判断是否是法定假日
* @date Created in 21:03 2019/1/31
**/
public boolean isLawHoliday(String calendar) throws Exception {
ChineseCalendarUtils.isValidDate(calendar);
if (lawHolidays.contains(calendar)) {
return true;
}
return false;
}
/**
* @author qyw
* @description 判断是否是周末
* @date Created in 21:03 2019/1/31
**/
public boolean isWeekends(String calendar) throws Exception {
ChineseCalendarUtils.isValidDate(calendar);
// 先将字符串类型的日期转换为Calendar类型
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(calendar);
Calendar ca = Calendar.getInstance();
ca.setTime(date);
if (ca.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY
|| ca.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
return true;
}
return false;
}
/**
* @author qyw
* @description 判断是否是需要额外补班的周末
* @date Created in 21:06 2019/1/31
**/
public boolean isExtraWorkday(String calendar) throws Exception {
ChineseCalendarUtils.isValidDate(calendar);
if (extraWorkdays.contains(calendar)) {
return true;
}
return false;
}
/**
* @author qyw
* @description 判断是否是休息日(包含法定节假日和不需要补班的周末)
* @date Created in 21:06 2019/1/31
**/
public boolean isHoliday(String calendar) throws Exception {
ChineseCalendarUtils.isValidDate(calendar);
// 首先法定节假日必定是休息日
if (this.isLawHoliday(calendar)) {
return true;
}
// 排除法定节假日外的非周末必定是工作日
if (!this.isWeekends(calendar)) {
return false;
}
// 所有周末中只有非补班的才是休息日
if (this.isExtraWorkday(calendar)) {
return false;
}
return true;
}
/**
* @author qyw
* @description 校验字符串是否为指定的日期格式,含逻辑严格校验,2007/02/30返回false
* @date Created in 21:06 2019/1/31
**/
private static boolean isValidDate(String str) {
boolean convertSuccess = true;
// 指定日期格式为四位年/两位月份/两位日期,注意yyyy-MM-dd区分大小写;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
// 设置lenient为false.
// 否则SimpleDateFormat会比较宽松地验证日期,比如2007/02/29会被接受,并转换成2007/03/01
format.setLenient(false);
format.parse(str);
} catch (ParseException e) {
convertSuccess = false;
}
return convertSuccess;
}
public String checkDate(String date) throws Exception {
if(isHoliday(date)){
return "-1";
}else{
return "0";
}
}
}
两个工具类配合使用就行,篇幅较长,建议CV到idea上阅读,支持2019全年度请假时间计算,如需支持其他年份,需要再行录入部分数据。
本文介绍了如何根据业务需求计算请假时长,考虑了节假日、双休、调休、午休等因素。通过两个工具类的配合,实现了2019全年请假时间计算,对于其他年份,需要额外录入数据。
&spm=1001.2101.3001.5002&articleId=97628533&d=1&t=3&u=db4998beab3f45ba8b84175124970ad5)
3022

被折叠的 条评论
为什么被折叠?



