Java 计算一段时间段内除去周六日、节假日的工作日数———超详细(全)

Java 计算一段时间段内除去周六日、节假日的工作日数‘’


实现功能提要: 本文章记录的是某段时间的起止时间段内的工作日,既是除去周六周日以及节假日日期的工作日数;
注释比较多,因为怕自己忘记,写的可能比较啰嗦~;


1、前端界面简介

其他的先不考虑,主要是由前台传递到后台的假期开始时间和结束时间;
在这里插入图片描述


2、后台处理代码

此段直接进入正题,处理代码我封装到Utils工具类中了,因此关于接收前台时间数据、方法的调用以及参数的传递就不在细说,只提一点就是:传到工具类中的参数有三个,分别是假期开始、假期结束时间以及假期信息表的service对象~

代码部分:

package cn.com.ikdo.oa.leave.utils;
/**
 * @Descript: 工作日计算
 */
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import cn.com.oa.leave.entity.OaAttendanceVacation; // 假期信息实体类
import cn.com.oa.leave.service.OaAttendanceVacationService; // 假期信息表的service对象

public class DutyDaysUtils {
	@SuppressWarnings("deprecation")
	public static float getDutyDays(Date startDate, Date endDate, OaAttendanceVacationService oaAttendanceService) {
		
		/* 
		此处 result 的返回值及其类型是因为数据库中与之相关的数据是float类型的,因此设置成这样,
		有需要的童鞋可以根据个人情况而定————设置成这样的目的是为了能存储带小数点的数字
		*/
		Float result = 0F;

		/*
		 此处一定要new两个时间对象进行接收传递来的参数,否则会在之后保存请假的起止日期时
		 发现用户选择的起止日期和数据库中的日期不一致,原因就在于下面的代码会操作开始日期
		 并使其发生改变,而结束日期不会变化,但是还是都统一处理一下的好(强迫症~)
		  */
		Date startDates = new Date(startDate.getTime());
		Date endDates = new Date(endDate.getTime());
		
		/* 
		此段主要是为了达到半天请假记录的处理,比如我是6月11日上午11点开始请假,那么就相
		当于我是早上请假,请假的第一天就会记为一个工作日,如果我是12点之后假期开始,
		那么就是半个工作日(如果想细分就需要自己在琢磨琢磨了),结束日期与之类似,但是需
		要注意的是,结束日期12点之前算是半个工作日,12点之后算是一个工作日,豫开始日期的正好相反
		*/
		SimpleDateFormat spf = new SimpleDateFormat("HH");
		String start = spf.format(startDates);
		String end = spf.format(endDates);
		int s = Integer.parseInt(start);
		int e = Integer.parseInt(end);
		// 开始时间大于12点的按半天算,小于12的按一天算
		if (s <= 12) {
			result = result + 1F;
		} else {
			result = result + 0.5F;
		}
		// 结束时间大于12点的按一天算,小于12的按半天算
		if (e <= 12) {
			result = result + 0.5F;
		} else {
			result = result + 1F;
		}

		/*
		重点问题:
		下面的此段代码是为了将date类型的yyyy-MM-dd HH:mm:ss格式转为 yyyy-MM-dd,实际是转化成
		yyyy-MM-dd 00:00:00
		
		转化的原因:
		时分秒参与while循环会产生bug:当起始时间的时分秒大于结束时间的时分秒时,一旦起止
		时间的年月日相等就会导致while循环结束,产生少计算一次的问题;
		 
		转化方法:
		通过处理将参与while循环的起止时间格式为年月日类型的:先通过date转为string类型的
		yyyy-MM-dd格式,再转成date类型的即可(转化方法想过使用更简便的,但是很无奈没找
		到,只能这么处理了,有更简便的童鞋可以告知一声~)
		*/
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		String dfStart = df.format(startDates);
		String dfEnd = df.format(endDates);
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		try {
			Date startparam = formatter.parse(dfStart);
			Date endparam = formatter.parse(dfEnd);
			// 每次循环的都查看计算日期是否超出结束日期
			while (startparam.compareTo(endparam) <= 0) {
				// 参与判断日期的星期码不等于周六且不等于周日的星期码
				if (startparam.getDay() != 6 && startparam.getDay() != 0) {
					// 此处需要注意,本人使用的去除节假日日期的方法是先将节假日的信息(主要
					//是节日假期起止时间)放入到数据库中,然后通过循环比对参与判断的日期是否在某个节日假期时间内;

					// 创建一个查询条件对象(没有此方法的可以自己手动将查询条件传递给SQL)
					LambdaQueryWrapper<OaAttendanceVacation> query = Wrappers.lambdaQuery();
					// 参与判断的日期大于等于节日假期的开始时间条件(OaAttendanceVacation为假期的实体对象,StartDay是假期开始时间)
					query.le(OaAttendanceVacation::getStartDay, startparam);
					// 参与判断的日期小于等于节日假期的开始时间条件(EndDay是假期截止时间)
					query.ge(OaAttendanceVacation::getEndDay, startparam);
					// 通过count方法查询是否存在符合条件的
					int count = oaAttendanceService.count(query);
					//	 若是count仍为0,则说明没有符合条件的,进一步说就是参与判断的日期不是节假日
					if (count == 0) {
						// 工作日计数参数加一
						result++;
					}
				}
				// 此天判断玩完了,对当前日期进行加一操作,使其变成下一天的日期参与下一轮判断
				startparam.setDate(startparam.getDate() + 1);
			}
		} catch (ParseException e1) {
			e1.printStackTrace();
		}

		/*
		到这里,只能说该统计的都统计了,但是还是有很多问题的,比如说:
		1、若是请假信息中起止时间为同一天的话就会出现多算的问题;
		2、若是请假信息中的开始、结束时间有为节假日的,也会出现多算的问题;
		3、若是请假信息中的起止时间有为周六日的,也会出现多算的问题;
		因此,下面就需要对请假信息中的起止时间进行梳理判断,判断起止时间是
		否是在同一天,并在是和否情况下再次判断起止时间是否为节假日;
		*/

		// 判断起止时间是否为同一天
		int isEq = 0;
		// 创建接收yyyy-MM-dd格式的date类型的起止时间对象,下面会用到
		Date paramS = new Date();
		Date paramE = new Date();
		try {
			// 经转化成yyyy-MM-dd格式的Date数据(注意,dfStart,dfStart是在上面处理成string类型的起止时间)
			Date startparam = formatter.parse(dfStart);
			Date endparam = formatter.parse(dfStart);
			// 直接比较起止时间是否相等
			if (startparam.equals(endparam)) {
				// 是同一天则改变isEq值
				isEq++;
			}
			// yyyy-MM-dd格式的date类型的起止时间数据放入相应对象用于下边的使用
			paramS = startparam;
			paramE = endparam;
		} catch (ParseException e1) {
			e1.printStackTrace();
		}
		if (isEq == 0) {// 起止时间不在同一天的情况下
			// 开始时间是否在节日假期范围内(OaAttendanceVacation、getStartDay、getEndDay均不在赘述,意思与上面一样)
			LambdaQueryWrapper<OaAttendanceVacation> queryStart = Wrappers.lambdaQuery();
			queryStart.ge(OaAttendanceVacation::getStartDay, paramS);
			queryStart.le(OaAttendanceVacation::getEndDay, paramS);
			int countStart = oaAttendanceService.count(queryStart);

			// 结束时间是否在节日假期范围内
			LambdaQueryWrapper<OaAttendanceVacation> queryEnd = Wrappers.lambdaQuery();
			queryEnd.ge(OaAttendanceVacation::getStartDay, paramE);
			queryEnd.le(OaAttendanceVacation::getEndDay, paramE);
			int countEnd = oaAttendanceService.count(queryEnd);

			// 判断开始时间不是周六日或节假日
			if (startDates.getDay() != 6 && startDates.getDay() != 0 && countStart == 0) {
				result = result - 1F;
			} else {// 开始时间在周六日或节假日
				if (s < 12) {
					result = result - 1F;
				} else {
					result = result - 0.5F;
				}
			}
			// 结束时间不是周六日或节假日
			if (endDates.getDay() != 6 && endDates.getDay() != 0 && countEnd == 0) {
				result = result - 1F;
			} else {// 结束时间在周六日或节假日
				if (e < 12) {
					result = result - 0.5F;
				} else {
					result = result - 1F;
				}
			}
		} else {// 起止时间在同一天的情况下
			// 开始时间是否处于假期内,只需要查询开始时间或者结束时间即可
			LambdaQueryWrapper<OaAttendanceVacation> queryStart = Wrappers.lambdaQuery();
			queryStart.ge(OaAttendanceVacation::getStartDay, paramS);
			queryStart.le(OaAttendanceVacation::getEndDay, paramS);
			int countStart = oaAttendanceService.count(queryStart);
			// 此天非节假日、周六日
			if (startDates.getDay() != 6 && startDates.getDay() != 0 && countStart == 0) {
				if (s < 12 && e < 12) {
					result = result - 2F;
				}
				if (s < 12 && e > 12) {
					result = result - 2F;
				}
				if (s > 12 && e > 12) {
					result = result - 2F;
				}
			} else {// 此天为节假日、周六日
				if (s < 12 && e < 12) {
					result = result - 1.5F;
				}
				if (s < 12 && e > 12) {
					result = result - 2F;
				}
				if (s > 12 && e > 12) {
					result = result - 1.5F;
				}
			}
		}
		return result;
	}
}

3、注:

  • 星期码:从星期一到星期日的星期码是1,2,3,4,5,6,0。其实就是星期几对应的类似于索引的一个数码(星期码这个名词是我自己想的,因为觉得挺贴切的。。。还有就是不知道它真叫什么~)
  • getDay()方法就是获得这一天的星期码(int类型的),其功能就是用于获取传入日期的星期码的;
  • getDay()方法已经不被官方继续支持使用了,从 JDK 1.1 开始,由 Calendar.get(Calendar.DAY_OF_WEEK) 取代,但是暂时还能用,有兴趣的可以换成Calendar试试;
  • 另外,里面有几段代码使用频率比较高,有兴趣的可以封装成方法直接调用;

pass:

  • 代码中主要是自己的思路,可能有点啰嗦,就是怕自己以后再看费劲,想着这会麻烦点,以后轻松点~

感悟:

  • 不要对不会的代码心里排斥,多看别人的代码,勇于面对自己的弱点、问题,只有这样才能让自己进步!

《END》

  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
可以使用以下步骤来计算两个日期之间排除法定节假日周六周日工作日天数: 1. 首先,创建一个包含所有法定节假日的列表。你可以根据你所在的国家或地区来确定这些日期。 2. 然后,创建一个方法来判断给定的日期是否为法定节假日。在该方法,你可以将给定的日期与法定节假日列表进行比较,如果日期匹配任何一个法定节假日,则返回true,否则返回false。 3. 接下来,创建一个方法来判断给定的日期是否为周末(即星期六或星期日)。你可以使用Java的Calendar类来获取给定日期的星期几,并判断是否为周末。 4. 然后,创建一个方法来计算两个日期之间工作日天数。在该方法,你可以使用一个循环来遍历两个日期之间的每一天。对于每一天,你需要判断它是否为法定节假日或周末,如果不是,则将工作日天数加1。 5. 最后,调用这个方法,并传入要计算的两个日期,即可得到排除法定节假日和周末的工作日天数。 以下是一个简单示例代码: ```java import java.util.Calendar; public class WorkingDaysCalculator { // 创建法定节假日列表 private static final String[] HOLIDAYS = { "2022-01-01", "2022-01-02", // 示例日期,请根据实际情况修改 // ... 添加其他法定节假日 }; // 判断给定日期是否为法定节假日 private static boolean isHoliday(String date) { for (String holiday : HOLIDAYS) { if (holiday.equals(date)) { return true; } } return false; } // 判断给定日期是否为周末 private static boolean isWeekend(String date) { Calendar calendar = Calendar.getInstance(); calendar.set(Integer.parseInt(date.substring(0, 4)), Integer.parseInt(date.substring(5, 7)) - 1, Integer.parseInt(date.substring(8))); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); return dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY; } // 计算两个日期之间工作日天数排除法定节假日和周末) public static int calculateWorkingDays(String startDate, String endDate) { int workingDays = 0; Calendar start = Calendar.getInstance(); start.set(Integer.parseInt(startDate.substring(0, 4)), Integer.parseInt(startDate.substring(5, 7)) - 1, Integer.parseInt(startDate.substring(8))); Calendar end = Calendar.getInstance(); end.set(Integer.parseInt(endDate.substring(0, 4)), Integer.parseInt(endDate.substring(5, 7)) - 1, Integer.parseInt(endDate.substring(8))); // 循环遍历两个日期之间的每一天 while (!start.after(end)) { String currentDate = String.format("%04d-%02d-%02d", start.get(Calendar.YEAR), start.get(Calendar.MONTH) + 1, start.get(Calendar.DAY_OF_MONTH)); // 判断当前日期是否为法定节假日或周末 if (!isHoliday(currentDate) && !isWeekend(currentDate)) { workingDays++; } // 将日期增加一天 start.add(Calendar.DAY_OF_MONTH, 1); } return workingDays; } public static void main(String[] args) { String startDate = "2022-01-01"; // 开始日期,请根据实际情况修改 String endDate = "2022-01-07"; // 结束日期,请根据实际情况修改 int workingDays = calculateWorkingDays(startDate, endDate); System.out.println("工作日天数:" + workingDays); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清风暖云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值