java 排除法定节假日以及正常周六日,计算两个Date相差的小时数

计算两个Date类型参数,相差的小时数。
如果不排除节假日周六日的话,处理起来非常easy,但是…如果要排除法定节假日,排除正常周六日,同时特殊支持法定的工作日(有一些周六日,国家强制正常上班),那么处理起来就非常麻烦,下面用基础的Date和Calendar实现
注意:如果开始或者截止时间属于休息日,对应当天处理小时数为0。例如:2018-2-14 8:00:00 到2018-2-15 10:00:00,2-15是国家规定放假时间,不算时间,只算2-14号的16个小时。可以根据你们自己项目组的需求,灵活的修改哦

/**
	 * 判断输入的年月日日期是否属于休息日
	 * @param date  需要判断的日期(年月日)
	 * @param lawHolidayList  国家规定放假的时间
	 * @param lawWorkList  国家规定的工作日期
	 * @return
	 */
	public static boolean isDayOff(Date date,List<Date> lawHolidayList,List<Date> lawWorkList){

		for(Date date1 :lawHolidayList){
			int c = date.compareTo(date1);
			if(c==0){
				//休息日
				return true;
			}
		}

		for(Date date1 :lawWorkList){
			int c = date.compareTo(date1);
			if(c==0){
				//工作日
				return false;
			}
		}

		return isZhouLiuZhouRiDate(date);
    }


	/**
	 * 判断时间是否属于正常周六日
	 * @param date
	 * @return
	 */
	public static boolean isZhouLiuZhouRiDate(Date date){

		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int week = cal.get(Calendar.DAY_OF_WEEK) - 1;
		//是否属于周六日
		boolean flag = (week == 0 || week == 6);
		return flag;

	}

	/**
	 * 排除国家法定的休息日、正常周六日,计算两个时间相差多少小时数(休息日当天时间为零处理)
	 * @param startTimeYYYYMMDDHHMMSS  年月日时分秒
	 * @param endTimeYYYYMMDDHHMMSS  年月日时分秒
	 * @param lawHolidayList
	 * @param lawWorkList
	 * @return
	 */
	public static long workHours(Date startTimeYYYYMMDDHHMMSS,
								 Date endTimeYYYYMMDDHHMMSS,
								 List<Date> lawHolidayList,
								 List<Date> lawWorkList) throws Exception {
		//开始时间转成年月日格式
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String strStartTimeYYYYMMDD = sdf.format(startTimeYYYYMMDDHHMMSS);
		Date startTimeYYYYMMDD = sdf.parse(strStartTimeYYYYMMDD);
		//开始时间是否属于休息日
		boolean startTimeIsDayOff = isDayOff(startTimeYYYYMMDD, lawHolidayList, lawWorkList);

		//结束时间转成年月日格式
		String strEndTimeYYYYMMDD = sdf.format(endTimeYYYYMMDDHHMMSS);
		Date endTimeYYYYMMDD = sdf.parse(strEndTimeYYYYMMDD);
		//结束时间是否属于休息日
		boolean endTimeIsDayOff = isDayOff(endTimeYYYYMMDD, lawHolidayList, lawWorkList);

		//分为4种情况
		if (startTimeIsDayOff) {
			if (!endTimeIsDayOff) {
				//开始时间在休息日里,结束时间不在休息日里(开始那天不计算小时数,结束那天计算小时数)
				Calendar cal = Calendar.getInstance();
				cal.setTime(startTimeYYYYMMDD);
				cal.add(Calendar.DAY_OF_MONTH, +1);
				Date validStartTimeYYYYMMDD = cal.getTime();
				Date validStartTimeYYYYMMDDTemp = validStartTimeYYYYMMDD;
				int skipDay = 0;

				//循环遍历开始时间之后的每一个日期
				while (validStartTimeYYYYMMDDTemp.compareTo(endTimeYYYYMMDDHHMMSS) != 1) {
					if (isDayOff(validStartTimeYYYYMMDDTemp, lawHolidayList, lawWorkList)) {
						skipDay += 1;
					}
					cal.add(Calendar.DAY_OF_MONTH, +1);
					validStartTimeYYYYMMDDTemp = cal.getTime();
				}

				return ((endTimeYYYYMMDDHHMMSS.getTime() - validStartTimeYYYYMMDD.getTime()) / (60 * 60 * 1000)) - skipDay * 24;
			} else {
				//开始时间在休息日里,结束时间也在休息日里(开始那天不计算小时数,结束那天也不计算小时数,看中间有多少个工作日)
					Calendar cal = Calendar.getInstance();
				cal.setTime(startTimeYYYYMMDD);
				cal.add(Calendar.DAY_OF_MONTH, +1);
				Date validStartTimeYYYYMMDD = cal.getTime();
				//工作日天数
				int workDays = 0;
				//循环遍历开始时间之后的每一个日期
				while (validStartTimeYYYYMMDD.compareTo(endTimeYYYYMMDDHHMMSS) != 1) {
					if (!isDayOff(validStartTimeYYYYMMDD, lawHolidayList, lawWorkList)) {
						workDays += 1;
					}
					cal.add(Calendar.DAY_OF_MONTH, +1);
					validStartTimeYYYYMMDD = cal.getTime();
				}
				return workDays * 24;
			}
		} else {
			if (endTimeIsDayOff) {

				int skipDay = 0;
				//开始时间不在休息日里,结束时间在休息日里
				Calendar cal = Calendar.getInstance();
				cal.setTime(startTimeYYYYMMDD);
				cal.add(Calendar.DAY_OF_MONTH, +1);
				Date validStartTimeYYYYMMDD = cal.getTime();
				while (validStartTimeYYYYMMDD.compareTo(endTimeYYYYMMDDHHMMSS) != 1) {
					if (!isDayOff(validStartTimeYYYYMMDD, lawHolidayList, lawWorkList)) {
						skipDay += 1;
					}
					cal.add(Calendar.DAY_OF_MONTH, +1);
					validStartTimeYYYYMMDD = cal.getTime();
				}

				Calendar ca = Calendar.getInstance();
				ca.setTime(startTimeYYYYMMDDHHMMSS);
				int startHour = ca.get(Calendar.HOUR_OF_DAY);
				return (24-startHour) + skipDay * 24;
			} else {
				//开始时间在不在休息日里,结束时间也不在休息日里
				int skipDay = 0;
				Calendar cal = Calendar.getInstance();
				cal.setTime(startTimeYYYYMMDD);
				cal.add(Calendar.DAY_OF_MONTH, +1);
				Date validStartTimeYYYYMMDD = cal.getTime();
				while (validStartTimeYYYYMMDD.compareTo(endTimeYYYYMMDDHHMMSS) != 1) {
					if (isDayOff(validStartTimeYYYYMMDD, lawHolidayList, lawWorkList)) {
						skipDay += 1;
					}
					cal.add(Calendar.DAY_OF_MONTH, +1);
					validStartTimeYYYYMMDD = cal.getTime();
				}
				return ((endTimeYYYYMMDDHHMMSS.getTime() - startTimeYYYYMMDDHHMMSS.getTime()) / (60 * 60 * 1000)) - skipDay * 24;
			}
		}
	}




	public static void main(String args[]) throws Exception{

		SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyy-MM-dd");
		List<Date> lawHolidayDate = new ArrayList<>();
		List<Date> lawWorkDate = new ArrayList<>();
		String [] lawHolidayDateStr =
				new String[] {
				        "2018-01-01",
						"2018-02-15",
						"2018-02-16",
						"2018-02-17",
						"2018-02-18",
						"2018-02-19",
						"2018-02-20",
						"2018-02-21",
						"2018-04-05",
						"2018-04-06",
						"2018-04-07",
						"2018-04-29",
						"2018-04-30",
						"2018-05-01",
						"2018-06-16",
						"2018-06-17",
						"2018-06-18",
						"2018-09-22",
						"2018-09-23",
						"2018-09-24",
						"2018-10-01",
						"2018-10-02",
						"2018-10-03",
						"2018-10-04",
						"2018-10-05",
						"2018-10-06",
						"2018-10-07",
						"2018-12-30",
						"2018-12-31",
						"2019-01-01",
						"2019-02-04",
						"2019-02-05",
						"2019-02-06",
						"2019-02-07",
						"2019-02-08",
						"2019-02-09",
						"2019-02-10",
						"2019-04-05",
						"2019-04-06",
						"2019-04-07",
						"2019-05-01",
						"2019-06-07",
						"2019-06-08",
						"2019-06-09",
						"2019-09-13",
						"2019-09-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"};
		String [] lawWorkDateStr =
				new String[] {
						"2018-02-11",
						"2018-02-24",
						"2018-04-08",
						"2018-04-28",
						"2018-09-29",
						"2018-09-30",
						"2018-12-29",
						"2019-02-02",
						"2019-02-03",
						"2019-09-29",
						"2019-10-12"};

		for(String str :lawHolidayDateStr){
			lawHolidayDate.add(yyyyMMdd.parse(str));
		}

		for(String str :lawWorkDateStr){
			lawWorkDate.add(yyyyMMdd.parse(str));
		}

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date startDate = sdf.parse("2018-02-22 8:45:10");
		Date endDate = sdf.parse("2018-02-24 7:10:10");


		System.out.println("相差小时数:"+workHours(startDate,endDate,lawHolidayDate,lawWorkDate));
	}

上面的例子,需要在项目里配置两种时间,一是国家法律规定的休息的时间,二是国家规定要正常上班的时间(例如一些周六日,为了十一的一天放假,调休前一个或者后一个周六日必须上班)。上面的例子是直接写死的2018/2019年的两种时间,自己项目的话,可以配置在配置文件或者数据库中

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您好,可以使用Java的Joda-Time库来计算日期之间的时间差,并排除法定节假日周六日以及工作日午休。下面是一个示例代码: ```java import org.joda.time.DateTime; import org.joda.time.Days; import org.joda.time.Duration; import org.joda.time.Interval; import org.joda.time.LocalDate; import org.joda.time.LocalTime; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class DateUtil { // 法定节假日列表 private static final List<LocalDate> HOLIDAYS = Arrays.asList( // 2021年节假日 new LocalDate(2021, 1, 1), // 元旦 new LocalDate(2021, 2, 11), // 春节 new LocalDate(2021, 2, 12), new LocalDate(2021, 2, 13), new LocalDate(2021, 2, 14), new LocalDate(2021, 2, 15), new LocalDate(2021, 2, 16), new LocalDate(2021, 2, 17), new LocalDate(2021, 4, 3), // 清明节 new LocalDate(2021, 5, 1), // 劳动节 new LocalDate(2021, 5, 2), new LocalDate(2021, 5, 3), new LocalDate(2021, 6, 12), // 端午节 new LocalDate(2021, 9, 19), // 中秋节 new LocalDate(2021, 10, 1), // 国庆节 new LocalDate(2021, 10, 2), new LocalDate(2021, 10, 3), new LocalDate(2021, 10, 4), new LocalDate(2021, 10, 5), new LocalDate(2021, 10, 6), new LocalDate(2021, 10, 7) ); // 工作日午休时间段 private static final Interval WORKDAY_LUNCH_TIME = new Interval( new LocalTime(12, 0, 0), new LocalTime(13, 0, 0) ); // 工作日上班时间段 private static final Interval WORKDAY_OFFICE_TIME = new Interval( new LocalTime(9, 0, 0), new LocalTime(18, 0, 0) ); /** * 计算两个日期相差的天数,排除法定节假日周六日以及工作日午休 * * @param startDate 开始日期 * @param endDate 结束日期 * @return 相差天数 */ public static int getDaysBetweenExcludingHolidays(LocalDate startDate, LocalDate endDate) { // 计算相差天数(包括开始日期和结束日期) int days = Days.daysBetween(startDate, endDate).getDays() + 1; // 排除法定节假日周六日以及工作日午休 LocalDate date = startDate; int excludedDays = 0; for (int i = 0; i < days; i++) { if (isHoliday(date) || isWeekend(date) || isWorkdayLunchTime(date)) { excludedDays++; } else if (isWorkdayOfficeTime(date)) { // 工作日并且不在午休时间段内 excludedDays += 0; } else { excludedDays++; } date = date.plusDays(1); } return days - excludedDays; } /** * 判断日期是否为法定节假日 * * @param date 日期 * @return 是否为法定节假日 */ private static boolean isHoliday(LocalDate date) { return HOLIDAYS.contains(date); } /** * 判断日期是否为周六日 * * @param date 日期 * @return 是否为周六日 */ private static boolean isWeekend(LocalDate date) { return date.dayOfWeek().get() == 6 || date.dayOfWeek().get() == 7; } /** * 判断日期是否为工作日午休时间段 * * @param date 日期 * @return 是否为工作日午休时间段 */ private static boolean isWorkdayLunchTime(LocalDate date) { DateTime dateTime = date.toDateTimeAtStartOfDay(); return WORKDAY_LUNCH_TIME.contains(dateTime); } /** * 判断日期是否为工作日上班时间段 * * @param date 日期 * @return 是否为工作日上班时间段 */ private static boolean isWorkdayOfficeTime(LocalDate date) { DateTime dateTime = date.toDateTimeAtStartOfDay(); return WORKDAY_OFFICE_TIME.contains(dateTime); } public static void main(String[] args) { LocalDate startDate = new LocalDate(2021, 4, 1); LocalDate endDate = new LocalDate(2021, 4, 8); int days = getDaysBetweenExcludingHolidays(startDate, endDate); System.out.println("相差天数:" + days); } } ``` 在上面的代码中,首先定义了法定节假日列表、工作日午休时间段以及工作日上班时间段。然后定义了四个私有方法,分别判断一个日期是否为法定节假日周六日、工作日午休时间段以及工作日上班时间段。最后,提供了一个公共方法 `getDaysBetweenExcludingHolidays`,该方法接收开始日期和结束日期两个参数,返回两个日期之间相差的天数,排除法定节假日周六日以及工作日午休时间段。最后在 `main` 方法中测试了一下该方法的使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

princeAladdin

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

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

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

打赏作者

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

抵扣说明:

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

余额充值