计算2个时间的工作小时(分钟)

计算2个时间的工作小时(分钟)

一 使用情景

比如xxx人 2020-04-30 08:00:00上班,5-1到5-5是节假日不上班,5月7日请假,2020-05-11 15:00:00后辞职。
此时我们需要计算出他们的工作小时。

二 主要逻辑

网上参考别人的计算,基本上都是2个时间相减,然后增加个单位。比如2个日期相差了几天,而我们要精确到小时或者分钟的时间,就会出现几千分钟,然后在开始时间上依次加一分钟判断是否是节假日,不是则增加一,循环上效率太低。
以下是我的思路:
忽略朝九晚五这样,都是按照24小时计算。可以在代码中修改
以情景为例则经过的时间,
2020-04-30 08:00:00 - 2020-04-30 23:59:59 【工作日】
2020-05-01 00:00:00 - 2020-05-01 23:59:59(法定节假日)
2020-05-02 00:00:00 - 2020-05-02 23:59:59(法定节假日)
2020-05-03 00:00:00 - 2020-05-03 23:59:59(法定节假日)
2020-05-04 00:00:00 - 2020-05-04 23:59:59(法定节假日)
2020-05-05 00:00:00 - 2020-05-05 23:59:59(法定节假日)
2020-05-06 00:00:00 - 2020-05-06 23:59:59 【工作日】
2020-05-07 00:00:00 - 2020-05-07 23:59:59(请假)
2020-05-08 00:00:00 - 2020-05-08 23:59:59 【工作日】
2020-05-09 00:00:00 - 2020-05-09 23:59:59(法定加班日)【工作日】
2020-05-10 00:00:00 - 2020-05-10 23:59:59(周末)
2020-05-11 00:00:00 - 2020-05-11 15:00:00 【工作日】
实际计算的时候,是5个工作日的时间相加。此时就考虑到了去除节假期,去除周末,去除自定义(如请假),增加加班日等情形。后面附上代码已经我的思路。

三 代码实现

首先判断2个日期毫秒值,相距了多少天,例子为13天
然后再开始时间上加一天,判断这天是不是工作日,如果是,开始计算当天用了多少时间
然后再加一天,依然判断是否是工作日,依次循环。
如果实际结束时间小于当天的结束时间,说明可以使用固定的结束时间,如6点下班,你5点就走了,就使用5。
代码执行时的效果就是如逻辑上那样走的。

	/**
	 * 计算两个日期之间的工作分钟
	 * 
	 * @param dt1
	 *            开始日期
	 * @param dt2
	 *            结束日期
	 * @return
	 */
	public static int getDifferMinute(String dt1, String dt2) {
		int second = 0;
		try {
			String beginTime = dt1;
			String endTime = dt2;
			// 时间格式器
			SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			// 日期格式器
			SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");

			Date date1 = sf.parse(dt1);
			Date date2 = sf.parse(dt2);
			Date date3 = dayFormat.parse(dt1);
			long daySec = 1000*60*60*24;
			Date datetemp = null;
			GregorianCalendar cal = new GregorianCalendar();
			cal.setTimeInMillis(date3.getTime());
			datetemp = cal.getTime();
			// 计算两个日期的间隔天数
			long differDays = getDifferDays(date1,date2);
			// 在开始日期上,依次增加天数,判断是否是工作日,如果是工作日则增加工作小时
			for (int i = 0; i <= differDays; i++) {
				// 判断新的一天是否是工作日
				if(i!=0) {					
					cal.add(Calendar.DAY_OF_MONTH, 1);
				}
				long l = cal.getTime().getTime() + daySec-1;
				// 判断是否是工作日
				boolean workindDay = isWorkindDay(cal.getTime());
				if(workindDay) {
					// 
					if(cal.getTime().before(date1)) {
						beginTime = dt1;
					}else {
					// 如果开始时间不需要从00:00:00开始,可以修改daySec这个,我是增加了一天的毫秒值
						beginTime = sf.format(cal.getTime());// 
					}
									
					// 新一天的结束时间,在实际结束时间之后,则结束时间才使用实际结束时间
					if(l > date2.getTime()) {
						endTime = dt2;
					}else {
					//  如果开始时间不需要到23:59:59,可以修改这个位置,可以给cal增加指定的小时
						endTime= sf.format(l);
					}
					
					// 结束时间必须在开始时间后
					if(sf.parse(endTime).after(sf.parse(beginTime))) {								
						second +=getDateSec(beginTime,endTime);
					}
					
				}			
			}					
			
		} catch (ParseException e) {
			logger.error("解析日期数值出错,传入的开始日期和结束日期格式出错!", e);
		}
		return second/60;
	}
	
	/**
	 * 返回两个日期之间的间隔天数
	 * 
	 * @param adate
	 *            开始时间
	 * @param bdate
	 *            结束时间
	 * @return 返回之间的间隔天数
	 */
	private static long getDifferDays(Date adate, Date bdate) {
		double d =  (bdate.getTime() - adate.getTime())/ (3600 * 24 * 1000) +0.5 ;		
		return Math.round(d);
	}

判断是否是工作日代码,其中的节假日和加班日由于涉及数据库就不黏贴了,主要就是{{春节开始时间,春节结束时间},{51开始时间,51结束时间}}这样的结构

/**
	 * 判断是否是工作日
	 * @param date1
	 * @return
	 */
	private static boolean isWorkindDay(Date date1) {
		boolean result =false;
		String[][] holidays = getHolidays(); //获取自定义节假日
		String[][] worktimes = getWorkingDays(); //获取自定义加班日

		// 计算节假日和自定义节假日
		SimpleDateFormat sf1 = new SimpleDateFormat("E");
		SimpleDateFormat sf2 = new SimpleDateFormat("yyyy-MM-dd");

		Date datetemp = null;
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTimeInMillis(date1.getTime());
		//cal.add(Calendar.HOUR_OF_DAY, i);
		datetemp = cal.getTime();
		String week = sf1.format(datetemp);
		// 如果是周一到周五,为正常工作日,校验是否是节假日
		if (!week.equals("星期六") && !week.equals("星期日")) {
			// 判断自定义的节假日
			boolean isHoliday = false;
			for (int j = 1; j < holidays.length; j++) {
				String d1 = holidays[j][0];
				String d2 = holidays[j][1];
				Date dt1 = null, dt2 = null;
				try {
					dt1 = sf2.parse(d1);
					dt2 = sf2.parse(d2);
				} catch (ParseException e) {
					logger.error(e.getMessage());
					logger.error("解析日期数值出错,节假日配置的开始日期和结束日期格式出错!日期值为:" + d1 + " 和 " + d2);
				}
				// 如果当前日期在定义的节假日范围内
				if ((datetemp.after(dt1) && datetemp.before(dt2))
					|| (datetemp.equals(dt1) && datetemp.equals(dt2))
					|| (datetemp.compareTo(dt1) >= 0 && datetemp.compareTo(dt2) <= 0)) {
					isHoliday = true;
					// 如果是周一到周五,但是是自定义节假日,说明不算工作日
					return false;
				}
			}			
				return true;		

		// 周末,判断是否是加班日
		}else if (week.equals("星期六") || week.equals("星期日")) {
			// 判断自定义的加班日
			boolean isOvertime = false;
			for (int j = 1; j < worktimes.length; j++) {
				String d1 = worktimes[j][0];
				String d2 = worktimes[j][1];
				Date dt1 = null, dt2 = null;
				try {
					dt1 = sf2.parse(d1);
					dt2 = sf2.parse(d2);
				} catch (ParseException e) {
					logger.error(e.getMessage());
					logger.error("解析日期数值出错,节假日配置的开始日期和结束日期格式出错!日期值为:" + d1 + " 和 " + d2);
				}
				// 如果当前日期在定义的加班日日范围内
				if ((datetemp.after(dt1) && datetemp.before(dt2))
					|| (datetemp.equals(dt1) && datetemp.equals(dt2))
					|| (datetemp.compareTo(dt1) >= 0 && datetemp.compareTo(dt2) <= 0)) {
					isOvertime = true;
					return isOvertime;
				}
			}

			return false;			
		}
		
	    return result;	
	}

  
    /**
	 * 计算同一个天内的2个时间,相隔多少秒
	 * 获取传入开始时间与结束时间相差的多少秒。传入的时间需要为同一天,如果没传结束时间,则计算到当天最后一秒
	 * @param date
	 * @return
	 */
	public static  long getDateSec(String beginTime,String endTime) {
		long sec = 0;
		try {
			int dayMis=1000*60*60*24;//一天的毫秒-1
			SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
			SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

			long beginSecond = dayFormat.parse(beginTime).getTime();// 获取一天的开始的毫秒值
			// 获取开始时间的毫秒值
			long currentTime = timeFormat.parse(beginTime).getTime();// 返回指定日期毫秒值			
			long endSecond = beginSecond + dayMis -1;// 获取当天的最后一秒
			// 计算结束时间的毫秒值
			if(endTime != null) {
				endSecond = timeFormat.parse(endTime).getTime();
			}
			// 日期结束时间-指定开始时间
			sec = (endSecond - currentTime)/1000;	
			//Log.info("开始时间["+beginTime+"]--结束时间["+endTime+"]--间隔时间["+sec/60+"]分钟");
			return sec;
		} catch (ParseException e) {
			logger.error("解析日期数值出错,传入的开始日期和结束日期格式出错!", e);
		}
		return sec;
	}

自定义的工作日或加班日是通用的。可以配置到一起,如果针对单人的,则再是否工作日逻辑里增加,如查询此人当天是否有请假。

四 总结

因为比较急,很多东西也还是可以优化的,作为记录自己一个小功能,希望对遇到同样业务的人有所帮助吧,有什么可以优化,或者有什么错误的也欢迎指导下,或者有更好的实现。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值