java判断一个Date时间在不在某段Date时间范围之内

            有时候我们会遇到这类问题,比如在OA系统提交年假申请时,系统如何校验当前提交的休假时间,有没有在之前的单据中提交并审批通过的(通过所有流程的年假单据通常会存在一张年假信息表里,记录了年假的开始结束日期)时间发生重叠呢?  下面我们讨论一下这个时间校验的问题:一个Date类型时间或一段Date类型时间在不在某段Date时间范围之中。

           举一个栗子:某员工在9月初提交了一条年假申请单(申请时间为9月6日上午至9月7日上午,1天半)并被终审通过了,而该员工后来又提交了一条年假申请单,可能由于粗心,忘记了9月7日上午已经请过年假了,又想把9月7日全天申请了,这个时候系统该如何进行校验呢?(系统不能让本单提交成功),以下为例子的真实应用场景。



 实现步骤分析:

         一、要实现本功能的前提条件是,数据库中存放审批通过的年假信息的表中的数据存储格式,是否满足业务需求


经过调查发现 存储 请假开始时间与结束时间的字段为 oracle 的 Timestamp 类型字段,而由于受数据库时间格式制约(需要进行设置),这种存储的时间数据在查询语句中判断不出上午或下午,看上图所示,虽然显示数据查询出上午下午,但是在查询语句条件中很难加入对上午下午的判断。故造成的影响是,当天的信息不得不取到后台中进行判断了(取出之后转成Date类型)。

后台执行的查询语句发现,之前的1天半年假,系统将其转化成两条记录记录存入年假信息表中(后台对年假以天为维度进行拆分的)

程序开始进行年假校验,参考代码如下

 //校验年假  
  //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);
	  }


checlAnnualLeave() 方法为 年假校验方法

/**
   * 检查年假
   * @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;
	}


通过以上方法,可以在特定场合下解决了年假校验的问题了。








 

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

景天

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

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

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

打赏作者

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

抵扣说明:

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

余额充值