java判斷一個Date時間在不在某段Date時間範圍之內
阿新 • • 發佈:2019-01-08
有時候我們會遇到這類問題,比如在OA系統提交年假申請時,系統如何校驗當前提交的休假時間,有沒有在之前的單據中提交併審批通過的(通過所有流程的年假單據通常會存在一張年假資訊表裡,記錄了年假的開始結束日期)時間發生重疊呢? 下面我們討論一下這個時間校驗的問題:一個Date型別時間或一段Date型別時間在不在某段Date時間範圍之中。
舉一個栗子:某員工在9月初提交了一條年假申請單(申請時間為9月6日上午至9月7日上午,1天半)並被終審通過了,而該員工後來又提交了一條年假申請單,可能由於粗心,忘記了9月7日上午已經請過年假了,又想把9月7日全天申請了,這個時候系統該如何進行校驗呢?(系統不能讓本單提交成功),以下為例子的真實應用場景。
實現步驟分析:
一、要實現本功能的前提條件是,資料庫中存放審批通過的年假資訊的表中的資料儲存格式,是否滿足業務需求
經過調查發現 儲存 請假開始時間與結束時間的欄位為 oracle 的 Timestamp 型別欄位,而由於受資料庫時間格式制約(需要進行設定),這種儲存的時間資料在查詢語句中判斷不出上午或下午,看上圖所示,雖然顯示資料查詢出上午下午,但是在查詢語句條件中很難加入對上午下午的判斷。故造成的影響是,當天的資訊不得不取到後臺中進行判斷了(取出之後轉成Date型別)。
後臺執行的查詢語句發現,之前的1天半年假,系統將其轉化成兩條記錄記錄存入年假資訊表中(後臺對年假以天為維度進行拆分的)
程式開始進行年假校驗,參考程式碼如下
checlAnnualLeave() 方法為 年假校驗方法//校驗年假 //fdChanged 申請人, mark1 >= , mark2 <= , fdStartDate 使用者錄入開始日期, fdEndDate 使用者錄入結束日期, fdStartNoon 使用者錄入 開始日期上下午標誌, fdEndNoon 使用者錄入結束日期上下午標誌 Map<String,String> fdReviewNoMap = checkAnnualLeave(fdChanged, mark1, mark2, fdStartDate, fdEndDate, fdStartNoon, fdEndNoon); StringBuffer info = new StringBuffer(); if(fdReviewNoMap.size() > 0){ Iterator<Entry<String,String>> iter = fdReviewNoMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); Object val = entry.getValue(); info.append(val).append(","); } System.out.println("本次年假申請時間與以前的年假申請單年假時間發生重疊,重疊的年假單據號為:"+info); map.put("info", "本次年假申請時間與以前的年假申請單年假時間發生重疊,重疊的年假單據號為:"+info); list.add(map); }
/**
* 檢查年假
* @param fdChanged 申請人
* @param mark1
* @param mark2
* @param fdStartDate 使用者錄入開始日期
* @param fdEndDate 使用者錄入結束日期
* @param fdStartNoon 使用者錄入 開始日期上下午標誌
* @param fdEndNoon 使用者錄入結束日期上下午標誌
* @return Map<String,String> fdReviewNoMap
* @throws Exception
*/
@SuppressWarnings("unchecked")
public Map<String,String> checkAnnualLeave(String fdChanged,String mark1,String mark2,String fdStartDate,String fdEndDate,
String fdStartNoon,String fdEndNoon) throws Exception{
//檢查本次年假是否已經請過了(走完流程的)
StringBuffer sql = new StringBuffer();
sql.append(" select t.fd_review_no,t.fd_start,t.fd_end,t.fd_count from km_attendanceinfol_leave t where 1=1 ");
sql.append(" and t.fd_holiday_type = '0' "); //假期型別為年假
sql.append(" and t.fd_type = '1' "); //流程型別 1: 請假 2: 外出 3: 銷假 4:調休
sql.append(" and t.fd_attendance_id = '").append(fdChanged).append("'"); //申請人
sql.append(" and to_char(t.fd_start,'yyyy-mm-dd hh12:mi:ss') ").append(mark1).append("'").append(fdStartDate).append(" 12:00:00'");
sql.append(" and to_char(t.fd_end,'yyyy-mm-dd hh12:mi:ss') ").append(mark2).append("'").append(fdEndDate).append(" 12:00:00'");
Session session = this.sysOrgPersonService.getBaseDao().getHibernateSession();
List<Object[]> querylist = session.createSQLQuery(sql.toString()).list();
System.out.println("查詢年假sql:"+sql.toString());
String fdReviewNo = ""; //年假單據號
Map<String,String> fdReviewNoMap = new HashMap<String,String>();
Timestamp tstart = null,tend = null;//開始時間,結束時間
Date dstart = null, dend = null;
int checkNoon = 0; //判斷資料是上午: 1 ,下午: 2 , 全天: 3
if(querylist.size() != 0){
for(Object[] obj : querylist){
fdReviewNo = (String)obj[0];
System.out.println(obj[0]+" start:"+obj[1]+" end:"+obj[2]+" count:"+obj[3]);
/**受Oracle 欄位型別Timestamp的條件限制(判斷不出上午或下午)只能將當天資料都查出來 , 所以並不是查出來單據就一定是重疊的,需要進行判斷
1.1 使用者輸入資料如果是同一天,則將錄入資料與後臺資料進行比較,看時間是否有重疊部分
1.2 使用者輸入資料跨天 ,要看是否有重疊的部分
請假開始日期 fdStartDate:2017-09-07 fdStartNoon:1
請假結束日期 fdEndDate:2017-09-07 fdEndNoon:1
當前時間:2017-09-07 00:00:00
當前時間:2017-09-07 12:00:00
*/
tstart = (Timestamp)obj[1]; //得到 Timestamp
tend = (Timestamp)obj[2];
dstart = tstart; //得到 date
dend = tend;
if(fdStartDate.equals(fdEndDate)){//使用者輸入資料如果是同一天
//將後臺資料與當天中午時間進行校驗,判斷資料是上午: 1 ,下午: 2 , 全天: 3
//判斷後臺數據是上午,下午 ,全天
checkNoon = checkForenoon(dstart,dend);
System.out.println("checkNoon:"+checkNoon);
switch(checkNoon){
case 1: //後臺資料是上午 ,開始校驗使用者輸入資料
if(fdStartNoon.equals("0") && fdEndNoon.equals("0") ){
//使用者輸入資料也是上午,時間發生重疊
fdReviewNoMap.put(fdReviewNo, fdReviewNo); //將單據號放入Map中(進行去重操作)
}else if(fdStartNoon.equals("0") && fdEndNoon.equals("1") ){
//使用者輸入資料是全天,時間發生重疊
fdReviewNoMap.put(fdReviewNo, fdReviewNo); //將單據號放入Map中(進行去重操作)
}
break;
case 2: //後臺資料是下午
if(fdStartNoon.equals("1") && fdEndNoon.equals("1") ){
//使用者輸入資料也是下午,時間發生重疊
fdReviewNoMap.put(fdReviewNo, fdReviewNo); //將單據號放入Map中(進行去重操作)
}else if(fdStartNoon.equals("0") && fdEndNoon.equals("1") ){
//使用者輸入資料是全天,時間發生重疊
fdReviewNoMap.put(fdReviewNo, fdReviewNo); //將單據號放入Map中(進行去重操作)
}
break;
case 3: //後臺資料是全天
//使用者輸入資料不管是上午或下午都會發生重疊,因為當天年假已經被用掉了
fdReviewNoMap.put(fdReviewNo, fdReviewNo); //將單據號放入Map中(進行去重操作)
break;
default: //後臺資料有錯誤
System.out.println("default 後臺資料有錯誤");
break;
}
}else{//使用者輸入資料跨天
//跨天的情況,跨天並不代表一定是重疊的,需要進行判斷是否有重疊部分,結合後臺資料 與 使用者輸入資料進行校驗
//使用者輸入時間資料比後臺資料範圍要大 因此需要 判斷 後臺時間在不在使用者輸入時間範圍內即可
if(checkInTime(dstart,dend,fdStartDate, fdStartNoon, fdEndDate, fdEndNoon)){
//後臺資料時間在使用者輸入時間範圍之內,有重疊
fdReviewNoMap.put(fdReviewNo, fdReviewNo); //將單據號放入Map中(進行去重操作)
}
}
}
System.out.println("fdReviewNoMap.size():"+fdReviewNoMap.size());
}
return fdReviewNoMap;
}
校驗時間範圍checkInTime()方法
/**
* 校驗時間範圍
* @param start 後臺資料開始時間
* @param end 後臺資料結束時間
* @param fdStartDate 使用者錄入開始日期
* @param fdStartNoon 使用者錄入 開始日期上下午標誌
* @param fdEndDate 使用者錄入結束日期
* @param fdEndNoon 使用者錄入結束日期上下午標誌
* @return true 後臺資料時間與使用者錄入時間有重疊 false 沒有重疊
* @throws ParseException
*/
public boolean checkInTime(Date start,Date end,String fdStartDate,String fdStartNoon,String fdEndDate,String fdEndNoon) throws ParseException{
//將使用者錄入開始日期與結束日期 轉成 Date型別
String startTime = fdStartNoon.equals("1") ? fdStartDate+" 12:00:00" : fdStartDate+" 00:00:00";
String endTimes = fdEndNoon.equals("1") ? fdEndDate+" 23:59:59" : fdEndDate+" 12:00:00";
Date beginTime = strFormatDate(startTime);
Date endTime = strFormatDate(endTimes);
//判斷後臺數據時間在不在使用者錄入時間範圍之中
boolean falg1 = belongCalendar(start,beginTime,endTime);
boolean falg2 = belongCalendar(end,beginTime,endTime);
if(falg1 && falg2){
return true;
}
return false;
}
判斷時間是否在某段時間段範圍內belongCalendar()
/**
* 判斷時間是否在時間段內
* @param nowTime
* @param beginTime
* @param endTime
* @return
*/
public boolean belongCalendar(Date nowTime, Date beginTime, Date endTime) {
Calendar date = Calendar.getInstance();
date.setTime(nowTime);
Calendar begin = Calendar.getInstance();
begin.setTime(beginTime);
Calendar end = Calendar.getInstance();
end.setTime(endTime);
if (date.after(begin) && date.before(end)) {
return true;
}else if(nowTime.compareTo(beginTime)==0 || nowTime.compareTo(endTime) == 0 ){
return true;
}else {
return false;
}
}
判斷某時間段屬於上午下午還是全天 checkForenoon()
/**
* 判斷某時間段屬於上午下午還是全天
* @param start 開始時間
* @param end 結束時間
* @return 1 是上午 2 是下午 3 全天 0 錯誤
* @throws ParseException
*/
private int checkForenoon(Date start,Date end) throws ParseException{
String sday = dateFormatStr(start);
Date middle = strFormatDate(sday+" 12:00:00"); //得到當天中午資料
if(start.compareTo(middle) < 0 && end.compareTo(middle) == 0){ //上午 start:2017-09-07 00:00:00.0 end:2017-09-07 12:00:00.0
return 1;
}
if(start.compareTo(middle) == 0 && end.compareTo(middle) > 0){ //下午 2016-08-05 12:00:00.0 end:2016-08-05 23:59:59.0
return 2;
}
if(start.compareTo(middle) < 0 && end.compareTo(middle) > 0){//全天 start:2017-09-06 00:00:00.0 end:2017-09-06 23:59:59.0
return 3;
}
return 0 ;
}
日期格式化方法 dateFormatStr()
/**
* 日期格式化
* @param Date
* return 格式化字串如 2017-09-07
* @param date
*/
private String dateFormatStr(Date date) {
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String time = format.format(date);
// System.out.println("時間:" + time);
return time;
}
字串日期轉date
/**
* 字串日期轉為Date
* @param ld
* @throws ParseException
*/
private Date strFormatDate(String ld) throws ParseException {
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date lendDate = format.parse(ld);
// System.out.println(lendDate);
return lendDate;
}
時間格式化
/**
* 時間格式化
* @param Date
* return 格式化字串如 2017-09-07 12:00:00
* @param date
*/
private String timeFormatStr(Date date) {
if(date == null)
return null;
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = format.format(date);
// System.out.println("時間:" + time);
return time;
}
通過以上方法,可以在特定場合下解決了年假校驗的問題了。