今天呢,我的头给我一个需求,就是让我做一个时间段是否重复的问题。刚开始打算自己写的,按照自己的思路来,什么时间段跨天了怎么验证是否重复都想了一下,没有想出来,没办法,百度了一下。原文链接在文章下面会给出。

一.需求背景

            需求背景就是一个工厂的工人有休息的固定时间。一天休息的时间段有多个,但是这些时间段是不可以有交集。

二. 前端页面jsp

            我们先来看一下效果图:

java 判断 两个集合是否含有交集_ico

            这个呢,就是维护rest表的页面图。休息时段名使用的是textbox,因为可以通过getText方法和setText轻松的得到这个文本框的值和设置文本框的文本值。

            而日期框使用的是Wdate easyui-validatebox日期验证框。

            直接贴一下jsp代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>

  <head>
    <%@ include file="../shared/head.jsp"%>
    <script src="<%=request.getContextPath()%>/plugins/easyui-1.5.1/jquery.easyui.min.js"></script>
    <script src="<%=request.getContextPath()%>/plugins/easyui-1.5.1/locale/easyui-lang-zh_CN.js"></script>
    <script src="<%=request.getContextPath()%>/js/hyapp.js"></script>
    <script src="<%=request.getContextPath()%>/js/hyapp.easyui-dialog.js"></script>
    <script src="<%=request.getContextPath()%>/js/basic/restPeriod.js"></script>
    <script type="text/javascript" src="<%=request.getContextPath()%>/plugins/My97DatePicker/WdatePicker.js"></script>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>休息时段管理</title>
  </head>

  <body class="easyui-layout" data-options="fit:true">
    <!-- 用来显示数据 -->
    <div data-options="region:'center',border:false" style="padding:2px;">
      <div>
        <a class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true" onclick="doAdd();" href="javascript:void(0);">添加</a>
        <a class="easyui-linkbutton" data-options="iconCls:'icon-edit',plain:true" onclick="doEdit();" href="javascript:void(0)">编辑</a>
        <a class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true" onclick="doRemove();" href="javascript:void(0)">删除</a>
      </div>

      <!-- 数据网格,用来显示数据 -->
      <table id="dataGrid" class="easyui-datagrid" data-options="singleSelect:false,rownumbers:true,
         fit:true,remoteSort:false,method:'get',pagination:true,pageSize:30,pageList:[30,100,500],
         onLoadSuccess:handleLoadSuccess,onDblClickRow:handleDblClick">
        <thead>
          <tr>
            <th data-options="field:'id',checkbox:true,width:100"></th>
            <th data-options="field:'restName',width:200,halign:'center',align:'left'">休息时段名称</th>
            <th data-options="field:'rest01Begin',width:200,halign:'center',align:'left'">休息时段1 开始时间</th>
            <th data-options="field:'rest01End',width:200,halign:'center',align:'left'">休息时段1 结束时间</th>
            <th data-options="field:'rest02Begin',width:200,halign:'center',align:'left'">休息时段2 开始时间</th>
            <th data-options="field:'rest02End',width:200,halign:'center',align:'left'">休息时段2 结束时间</th>
            <th data-options="field:'rest03Begin',width:200,halign:'center',align:'left'">休息时段3 开始时间</th>
            <th data-options="field:'rest03End',width:200,halign:'center',align:'left'">休息时段3 结束时间</th>
            <th data-options="field:'rest04Begin',width:200,halign:'center',align:'left'">休息时段4 开始时间</th>
            <th data-options="field:'rest04End',width:200,halign:'center',align:'left'">休息时段4 结束时间</th>
            <th data-options="field:'rest05Begin',width:200,halign:'center',align:'left'">休息时段5 开始时间</th>
            <th data-options="field:'rest05End',width:200,halign:'center',align:'left'">休息时段5 结束时间</th>
            <th data-options="field:'rest06Begin',width:200,halign:'center',align:'left'">休息时段6 开始时间</th>
            <th data-options="field:'rest06End',width:200,halign:'center',align:'left'">休息时段6 结束时间</th>
            <th data-options="field:'rest07Begin',width:200,halign:'center',align:'left'">休息时段7 开始时间</th>
            <th data-options="field:'rest07End',width:200,halign:'center',align:'left'">休息时段7 结束时间</th>
            <th data-options="field:'rest08Begin',width:200,halign:'center',align:'left'">休息时段8 开始时间</th>
            <th data-options="field:'rest08End',width:200,halign:'center',align:'left'">休息时段8 结束时间</th>
            <th data-options="field:'rest09End',width:200,halign:'center',align:'left'">休息时段9 开始时间</th>
            <th data-options="field:'rest09Begin',width:200,halign:'center',align:'left'">休息时段9 结束时间</th>
            <th data-options="field:'remark',width:200,halign:'center',align:'left'">备注</th>
          </tr>
        </thead>
      </table>
    </div>
    <!-- 添加框 -->
    <div id="addDialog" class="easyui-dialog" data-options="title:'增加或编辑',modal:true,closed:true,
       buttons:'#dialog-buttons'" style="width:580px; height:400px;">
      <form id="addForm" name="addForm">
        <input id="id" name="id" type="hidden" value="" />
        <table>
          <tr>
            <td> </td>
          </tr>
          <tr>
            <td align="right" width="70"> </td>
            <td align="right" width="80">休息时段名:</td>
            <td>
              <input id="restName" class="easyui-textbox" data-options="required:true" style="width:140px">
            </td>
          </tr>

          <tr>
            <td align="right" width="70">休息时段1</td>
            <td align="right" width="80">开始时间:</td>
            <td>
              <input id="rest01Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
            <td align="right" width="80">结束时间</td>
            <td>
              <input id="rest01End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
          </tr>

          <tr>
            <td align="right" width="70">休息时段2</td>
            <td align="right" width="80">开始时间:</td>
            <td>
              <input id="rest02Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
            <td align="right" width="80">结束时间</td>
            <td>
              <input id="rest02End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
          </tr>

          <tr>
            <td align="right" width="70">休息时段3</td>
            <td align="right" width="80">开始时间:</td>
            <td>
              <input id="rest03Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
            <td align="right" width="80">结束时间</td>
            <td>
              <input id="rest03End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
          </tr>

          <tr>
            <td align="right" width="70">休息时段4</td>
            <td align="right" width="80">开始时间:</td>
            <td>
              <input id="rest04Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
            <td align="right" width="80">结束时间</td>
            <td>
              <input id="rest04End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
          </tr>

          <tr>
            <td align="right" width="70">休息时段5</td>
            <td align="right" width="80">开始时间:</td>
            <td>
              <input id="rest05Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
            <td align="right" width="80">结束时间</td>
            <td>
              <input id="rest05End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
          </tr>

          <tr>
            <td align="right" width="70">休息时段6</td>
            <td align="right" width="80">开始时间:</td>
            <td>
              <input id="rest06Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
            <td align="right" width="80">结束时间</td>
            <td>
              <input id="rest06End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
          </tr>

          <tr>
            <td align="right" width="70">休息时段7</td>
            <td align="right" width="80">开始时间:</td>
            <td>
              <input id="rest07Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
            <td align="right" width="80">结束时间</td>
            <td>
              <input id="rest07End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
          </tr>

          <tr>
            <td align="right" width="70">休息时段8</td>
            <td align="right" width="80">开始时间:</td>
            <td>
              <input id="rest08Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
            <td align="right" width="80">结束时间</td>
            <td>
              <input id="rest08End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
          </tr>

          <tr>
            <td align="right" width="70">休息时段9</td>
            <td align="right" width="80">开始时间:</td>
            <td>
              <input id="rest09Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
            <td align="right" width="80">结束时间</td>
            <td>
              <input id="rest09End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
            </td>
          </tr>
        </table>
      </form>
    </div>
    <!-- 按钮工具栏 -->
    <div id="dialog-buttons">
      <a href="javascript:void(0);" class="easyui-linkbutton" data-options="iconCls:'icon-ok'" onclick="executeAdd()">确定</a>
      <a href="javascript:void(0);" class="easyui-linkbutton" data-options="iconCls:'icon-no'" onclick="javascript:$('#addDialog').dialog('close');">取消</a>
    </div>

  </body>

</html>

三.js代码

             当然了,最终的实现肯定是要靠js代码了。

$(function() {
    doSearch();
});

function doSearch() {
    hyapp.ajaxPost(hyapp.getContextPath() + "/basic/restPeriod/getRestList", {},
        function(result) {
            $("#dataGrid").datagrid({
                loadFilter: pagerFilter
            }).datagrid("loadData", result);
        },
        function(xhr, status) {
            hyapp.showError("错误", "加载失败!")
        })
}

/**
 * 相应添加
 */
function doAdd() {
    $('#addForm').form('clear'); //清空表单中所有输入框中的值。
    openAddDialog();
}

/**
 * 打开添加对话框
 */
function openAddDialog() {
    $("#addDialog").dialog("open");
}

/**
 * 得到对话框的数据
 */
function getDialogData() {
    var obj = {};
    obj.id = $("#id").val();
    obj.restName = $("#restName").textbox("getText");
    obj.rest01Begin = $('#rest01Begin').val();
    obj.rest01End = $('#rest01End').val();
    obj.rest02Begin = $('#rest02Begin').val();
    obj.rest02End = $('#rest02End').val();
    obj.rest03Begin = $('#rest03Begin').val();
    obj.rest03End = $('#rest03End').val();
    obj.rest04Begin = $('#rest04Begin').val();
    obj.rest04End = $('#rest04End').val();
    obj.rest05Begin = $('#rest05Begin').val();
    obj.rest05End = $('#rest05End').val();
    obj.rest06Begin = $('#rest06Begin').val();
    obj.rest06End = $('#rest06End').val();
    obj.rest07Begin = $('#rest07Begin').val();
    obj.rest07End = $('#rest07End').val();
    obj.rest08Begin = $('#rest08Begin').val();
    obj.rest08End = $('#rest08End').val();
    obj.rest09Begin = $('#rest09Begin').val();
    obj.rest09End = $('#rest09End').val();
    return obj;
}

/**
 * 执行添加
 */
function executeAdd() {
    if(!$("#addForm").form("validate")) {
        return;
    }
    var obj = getDialogData();
    var result = timeJudgement();
    if(result != "false") {
        hyapp.showInfo("提示", result);
        return;
    }
    if(obj.id != null) {
        hyapp.ajaxPost(hyapp.getContextPath() + "/basic/restPeriod/addOrEditRest", obj, function(result) {
            if(result.success) {
                $("#addDialog").dialog("close");
                doSearch();
                hyapp.showInfo("提示", result.msgText);
            }
        }, function(result) {
            hyapp.showInfo("异常", result.msgText);
        });
    }

}

/**
 * 时间段是否合适判断
 * @returns {String}
 */
function timeJudgement() {
    var time = [];
    time[0] = $('#rest01Begin').val();
    time[1] = $('#rest01End').val();
    time[2] = $('#rest02Begin').val();
    time[3] = $('#rest02End').val();
    time[4] = $('#rest03Begin').val();
    time[5] = $('#rest03End').val();
    time[6] = $('#rest04Begin').val();
    time[7] = $('#rest04End').val();
    time[8] = $('#rest05Begin').val();
    time[9] = $('#rest05End').val();
    time[10] = $('#rest06Begin').val();
    time[11] = $('#rest06End').val();
    time[12] = $('#rest07Begin').val();
    time[13] = $('#rest07End').val();
    time[14] = $('#rest08Begin').val();
    time[15] = $('#rest08End').val();
    time[16] = $('#rest09Begin').val();
    time[17] = $('#rest09End').val();

    for(var i = 0; i < time.length; i = i + 2) {
        if((time[i] == "" && time[i + 1] == "")) {
            continue;
        }

        if((time[i] != "" && time[i + 1] == "") ||
            (time[i] == "") && (time[i + 1] != "")) {
            return "请把时间段填写完整!";
        }

        if(time[i] == time[i + 1]) {
            return "开始和结束时间不能相同!";
        }
    }

    for(var i = 0; i < time.length; i = i + 2) {
        if(time[i] == "" || time[i + 1] == "") {
            continue;
        }

        for(var j = i + 2; j < time.length; j = j + 2) {
            if(time[j] == "" || time[j + 1] == "") {
                continue;
            }
            var flag = checkTime(time[i], time[i + 1], time[j], time[j + 1]);
            if(flag) {
                return "时间段冲突!";
            }
        }
    }
    return "false";
}

/**
 * 删除
 */
function doRemove() {
    var selectRows = $("#dataGrid").datagrid("getSelections");
    if(selectRows.length <= 0) {
        hyapp.showInfo("提示", "请选择要操作的数据!");
        return;
    }
    var idList = [];
    for(var i = 0; i < selectRows.length; i++) {
        idList.push(selectRows[i].id);
    }
    hyapp.showConfirm('请确认', '您确定要删除当前选中数据吗?', function() {
        hyapp.ajaxPost(hyapp.getContextPath() + "/basic/restPeriod/removeRest", idList,
            function(result) {
                doSearch();
                hyapp.showInfo("提示", result.msgText);
            },
            function(xhr, status) {
                hyapp.showError("错误", result.msgText)
            });
    });
}

/**
 * 编辑
 */
function doEdit() {
    var selRows = $('#dataGrid').datagrid('getSelections');
    if(selRows.length == 1) {
        openEditDialog(selRows[0]);
    } else {
        if(selRows.length == 0) {
            hyapp.showInfo("提示", "请选择要操作的数据!");
        } else {
            hyapp.showInfo("提示", "请选择一条数据!");
        }
    }
}

/**
 * 清空编辑框
 */
function clearDialog() {
    $('#addForm').form('clear');
}

/**
 * 打开编辑对话框
 */
function openEditDialog(row) {
    $('#addForm').form('clear');
    if(row) {
        $('#id').val(row.id);
        $("#restName").textbox("setText", row.restName);
        $('#rest01Begin').val(row.rest01Begin);
        $('#rest01End').val(row.rest01End);
        $('#rest02Begin').val(row.rest02Begin);
        $('#rest02End').val(row.rest02End);
        $('#rest03Begin').val(row.rest03Begin);
        $('#rest03End').val(row.rest03End);
        $('#rest04Begin').val(row.rest04Begin);
        $('#rest04End').val(row.rest04End);
        $('#rest05Begin').val(row.rest05Begin);
        $('#rest05End').val(row.rest05End);
        $('#rest06Begin').val(row.rest06Begin);
        $('#rest06End').val(row.rest06End);
        $('#rest07Begin').val(row.rest07Begin);
        $('#rest07End').val(row.rest07End);
        $('#rest08Begin').val(row.rest08Begin);
        $('#rest08End').val(row.rest08End);
        $('#rest09Begin').val(row.rest09Begin);
        $('#rest09End').val(row.rest09End);
    }
    $('#addForm').form('validate');
    $('#addDialog').dialog('open');
}

/**
 * 加载完成后
 */
function handleLoadSuccess(data) {
    $('#dataGrid').datagrid('clearSelections');
}

/**
 * 双击
 */
function handleDblClick(index, row) {
    $('#dataGrid').datagrid("unselectAll");
    $('#dataGrid').datagrid("selectRow", index);
    //    console.log(index);
    openEditDialog(row);
}

/**
 * 没有跨天时,验证是否冲突。
 * @param a
 * @param b
 * @param x
 * @param y
 * @returns {Boolean}
 */
function check(a, b, x, y) {
    if(y < a || b < x) {
        return false;
    } else {
        return true;
    }
}
/**
 * 
 * @param a
 * @param b
 * @param x
 * @param y
 * @returns {Boolean}
 */
function checkTime(a, b, x, y) {
    var times1 = [],
        times2 = [];
    if(a < b) {
        //未跨天
        times1.push([a, b]);
    } else {
        //跨天
        times1.push([a, "24:00"], ["00:00", b]);
    }

    if(x < y) {
        times2.push([x, y]);
    } else {
        times2.push([x, "24:00"], ["00:00", y]);
    }
    //循环比较时间段是否冲突
    for(var i = 0; i < times1.length; i++) {
        for(var j = 0; j < times2.length; j++) {
            if(check(times1[i][0], times1[i][1], times2[j][0], times2[j][1])) {
                return true;
            }
        }
    }
    return false;
}

 

  这里最重要的就是check方法和checkTime方法了,check方法是仅用来比较2个时间段是否有交集,而且这两个时间段都没有进行跨天的(也就是结束时间>起始时间)。

                  那么跨天的时间段怎么验证是否有交集呢?我们可以把跨天的时间段分为两部分,一部分是起始时间——24:00,另一部分是00:00——结束时间,所以我们只需要验证一个时间段例如2:00——6:00和这两个时间段没有交接即可(注意是3个时间段互相没有交集),这样就可以说明这个2:00——6:00的时间段和这个跨天的时间段没有交集了。

                   另外,需要注意的是,在进行校验的时候,验证时间段的起始和结束是否存在用的都是time[i]==" ",用的是空串的形式,这是因为通过 obj.rest01End = $('#rest01End').val();得到的数据是字符串的形式,如果在页面没有选择时间,那么得到的是一个空字符串“ ”。下面的数组就是我在前天debug获取的。

  1. 0: "18:30"
  2. 1: "19:00"
  3. 2: ""
  4. 3: ""
  5. 4: " "
  6. 5: " "
  7. 6: " "
  8. 7: " "
  9. 8: " "
  10. 9: " "
  11. 10: " "
  12. 11: " "
  13. 12: " "
  14. 13: " "
  15. 14: " "
  16. 15: " "
  17. 16: " "
  18. length: 17
  19. __proto__: Array(0)

                  那么这里又要有疑问了,既然是字符串那么是怎么比较大小的呢?

                  其实字符串的比较是按ASCII码的大小来比较的。从左到右逐位比较字符的ASCII码,只要分出大小,比较即结束。例如:

alert("2">"222");          为:false
alert("3">"222");          为:true

                   数字是这样,字符串也是如此,“ccc”肯定是要大于“aaa”的,既 “ ccc ” > " aaa "。

四.和博客不想关的东西

             这里说一个和这篇博客没有关系的几个东西。

            1.combobox下拉框,读取数据是从json数组中读取的。通过valueField属性来指定每一个下拉框的value值,通过textField来指定每个下拉框中的文本值。如果这个combobox下拉框在一个form表单中,当我们清空这个表单内的值时( $('#addForm').form('clear');),会清空这个combobox下拉框的值,而不是清空这个下拉框读取数据的json数组。所以在页面的体现就是当form表单被清空后,下拉框中的文本值会被清空,但是下拉框面板中的值依旧存在,当我们指定赋值value的时候,对应value的值会出现在下拉框的text中。
          2. form表单的clear()方法,用于清空表单中所有输入项的value值。reset()方法,如果输入框有 默认值,则恢复到其默认的value值,否则清空value值。
          3.动态删除集合中的数据是会导致出现问题的。                                                                                                          

          4.$.messager对象可以用来提示信息,通常可以在页面向用户显示提示框。