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》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章