JavaScript 检查时间范围是否重叠
JavaScript check if time ranges overlap
例如,我有一个包含 2 个对象的数组(myObject1 和 myObject2 如)。现在,当我添加第三个对象时,我将检查时间范围是否重叠。实际上,我不知道如何以高性能的方式做到这一点。
var myObjectArray = [];
var myObject1 = {};
myObject1.startTime = '08:00';
myObject1.endTime = '12:30';
...
var myObject2 = {};
myObject2.startTime = '11:20';
myObject2.endTime = '18:30';
...
myObjectArray.push(myObject1);
myObjectArray.push(myObject2);
假设我们有一些间隔
const INTERVALS = [
['14:00', '15:00'],
['08:00', '12:30'],
['12:35', '12:36'],
['13:35', '13:50'],
];
如果我们想将新的间隔添加到此列表中,我们应该检查新间隔是否与其中一些不重叠。
您可以循环低谷间隔并检查新的间隔是否与其他间隔重叠。请注意,在比较间隔时,如果您确定日期对象与可以将时间转换为数字的日期相同,则不需要 Date 对象:
function convertTimeToNumber(time) {
const hours = Number(time.split(':')[0]);
const minutes = Number(time.split(':')[1]) / 60;
return hours + minutes;
}
在两种情况下,间隔不重叠:
- 之前 (a
a b
|----------|
c d
|----------|
- 在 where (a> c && a> d) && (b>
- c && b> d):
a b
|----------|
c d
|----------|
因为总是c < d
,所以说不重叠间隔的条件是(a < c && b < c) || (a > d && b > d)
就足够了,因为总是a < b
,所以说这个条件等价于就足够了:
b < c || a > d
对这个条件的否定应该给我们一个重叠区间的条件。根据德摩根定律,它是:
b >= c && a <= d
请注意,在这两种情况下,间隔都不能相互"接触",这意味着 5:00-8:00 和 8:00-9:00 将重叠。如果要允许它,条件应该是:
b > c && a < d
至少需要考虑 5 种重叠间隔的情况:
a b
|----------|
c d
|----------|
a b
|----------|
c d
|----------|
a b
|----------|
c d
|--------------------|
a b
|--------------------|
c d
|----------|
a b
|----------|
c d
|----------|
带有额外添加和排序间隔函数的完整代码如下:
const INTERVALS = [
['14:00', '15:00'],
['08:00', '12:30'],
['12:35', '12:36'],
['13:35', '13:50'],
];
function convertTimeToNumber(time) {
const hours = Number(time.split(':')[0]);
const minutes = Number(time.split(':')[1]) / 60;
return hours + minutes;
}
// assuming current intervals do not overlap
function sortIntervals(intervals) {
return intervals.sort((intA, intB) => {
const startA = convertTimeToNumber(intA[0]);
const endA = convertTimeToNumber(intA[1]);
const startB = convertTimeToNumber(intB[0]);
const endB = convertTimeToNumber(intB[1]);
if (startA > endB) {
return 1
}
if (startB > endA) {
return -1
}
return 0;
})
}
function isOverlapping(intervals, newInterval) {
const a = convertTimeToNumber(newInterval[0]);
const b = convertTimeToNumber(newInterval[1]);
for (const interval of intervals) {
const c = convertTimeToNumber(interval[0]);
const d = convertTimeToNumber(interval[1]);
if (a < d && b > c) {
console.log('This one overlap: ', newInterval);
console.log('with interval: ', interval);
console.log('----');
return true;
}
}
return false;
}
function isGoodInterval(interval) {
let good = false;
if (interval.length === 2) {
// If you want you can also do extra check if this is the same day
const start = convertTimeToNumber(interval[0]);
const end = convertTimeToNumber(interval[1]);
if (start < end) {
good = true;
}
}
return good;
}
function addInterval(interval) {
if (!isGoodInterval(interval)) {
console.log('This is not an interval');
return;
}
if (!isOverlapping(INTERVALS, interval)) {
INTERVALS.push(interval);
// you may also want to keep those intervals sorted
const sortedIntervals = sortIntervals(INTERVALS);
console.log('Sorted intervals', sortedIntervals);
}
}
// --------------------------------------
const goodIntervals = [
['05:31', '06:32'],
['16:00', '17:00'],
['12:31', '12:34']
];
let goodCount = 0;
for (const goodInterval of goodIntervals) {
if (!isOverlapping(INTERVALS, goodInterval)) {
goodCount += 1
}
}
console.log('Check good intervals: ', goodCount === goodIntervals.length);
// --------------------------------------
const ovelappingIntervals = [
['09:30', '12:40'],
['05:36', '08:50'],
['13:36', '13:37'],
['06:00', '20:00'],
['14:00', '15:00']
]
let badCount = 0;
for (const badInterval of ovelappingIntervals) {
if (isOverlapping(INTERVALS, badInterval)) {
badCount += 1
}
}
console.log('Check bad intervals: ', badCount === ovelappingIntervals.length);
// --------------------------------------
addInterval(goodIntervals[0])
你可以尝试这样的事情:
var timeList = [];
function addTime() {
var startTime = document.getElementById("startTime").value;
var endTime = document.getElementById("endTime").value;
if (validate(startTime, endTime)){
timeList.push({
startTime: startTime,
endTime: endTime
});
print(timeList);
document.getElementById("error").innerHTML = "";
}
else
document.getElementById("error").innerHTML = "Please select valid time";
}
function validate(sTime, eTime) {
if (+getDate(sTime) < +getDate(eTime)) {
var len = timeList.length;
return len>0?(+getDate(timeList[len - 1].endTime) < +getDate(sTime) ):true;
} else {
return false;
}
}
function getDate(time) {
var today = new Date();
var _t = time.split(":");
today.setHours(_t[0], _t[1], 0, 0);
return today;
}
function print(data){
document.getElementById("content").innerHTML = "<pre>" + JSON.stringify(data, 0, 4) + "</pre>";
}
<input type="text" id="startTime" />
<input type="text" id="endTime" />
<button onclick="addTime()">Add Time</button>
<p id="error"></p>
<div id="content"></div>
将 moment-js 与矩范围一起使用(损坏的引用)
测试示例:
const range1 = moment.range(a, c);
const range2 = moment.range(b, d);
range1.overlaps(range2); // true
查看 https://github.com/rotaready/moment-range#overlaps 中的更多示例
请注意,要使上面的代码正常工作,也许您首先要执行以下操作:
<script src="moment.js"></script>
<script src="moment-range.js"></script>
window['moment-range'].extendMoment(moment);
网页代码
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-range/2.2.0/moment-range.min.js"></script>
JavaScript 代码
var range = moment.range(new Date(year, month, day, hours, minutes), new Date(year, month, day, hours, minutes));
var range2 = moment.range(new Date(year, month, day, hours, minutes), new Date(year, month, day, hours, minutes));
range.overlaps(range2); // true or flase
非常简洁的解决方案,momentjs
带有大量的日期和时间实用程序。
使用 JavaScript Date() 对象来存储时间,然后比较它们,如果 object1 的结束时间大于 object2 的开始时间,则它们是重叠的。您可以使用运算符>比较它们。
date1.getTime() > date2.getTime()
此处给出的演示
Date 对象的用法
要确定时间范围是否与其他时间范围重叠,您可以同时使用moment.js
库和moment-range
库。
首先安装moment-js
和moment-range
假设您有一个包含示例对象的 INTERVALS 数组:
const INTERVALS = [
{ START: 0, END: 10 },
{ START: 12, END: 30 },
...
]
您可以使用以下函数:
const validateIntervalOverlaps = () => {
if (INTERVAL_START && INTERVAL__END) {
const timeInterval = moment.range(moment(INTERVAL_START), moment(INTERVAL_ENDS))
const overlappingInterval = INTERVALS.find(intervalItem => {
const interval = moment.range(moment(intervalItem.START), moment(intervalItem.END))
return timeInterval.overlaps(interval)
})
return overlappingInterval
}
}
接下来,您可以执行需要对重叠间隔执行的操作:)F.e. 确定它是否存在或以任何其他方式使用它。祝你好运!
这里有一些可能有效的方法。
// check if time overlaps with existing times
for (var j = 0; j < times.length; j++) {
let existing_start_time = moment(this.parseDateTime(this.times[j].start_time)).format();
let existing_end_time = moment(this.parseDateTime(this.times[j].end_time)).format();
// check if start time is between start and end time of other times
if (moment(start_time).isBetween(existing_start_time, existing_end_time)) {
times[i].error = 'Time overlaps with another time';
return false;
}
// check if end time is between start and end time of other times
if (moment(end_time).isBetween(existing_start_time, existing_end_time)) {
times[i].error = 'Time overlaps with another time';
return false;
}
}
https://momentjs.com/
您可以通过尝试将时间范围合并到现有时间范围来检查是否存在重叠,如果合并后时间范围的总计数减少,则存在重叠。
我发现了以下文章,可能有助于处理合并范围
- 合并具有重叠值的数组
- 合并范围
- 访问布局信息是否也会导致浏览器重排
- 当包含另一个asp文件时,是否也包含所有引用的样式和脚本页面
- 如何检测是否有溢出
- jQuery中是否内置了任何字符串格式化函数
- 是否有任何snippet或jQuery插件可以列出easylist.txt模式匹配的DOM中的所有元素
- 测试索引值是否等于某个数字的倍数
- Javascript 检查范围是否重叠
- 检查两个或多个 DOM 元素是否重叠
- 正在检测Html元素是否与另一个Html元件重叠
- 如何检查给定的非凸区域是否与给定矩形完全重叠
- JavaScript 检查时间范围是否重叠
- 是否可以使jQuery单击事件触发播放声音重叠的函数
- 确定一个节点是否与另一个节点重叠
- 是否有可能使整个img可点击,即使它通过z-index与另一个元素重叠
- 测试一个点是否与画布上的一个字符重叠
- 如何检测一个元素是否被另一个元素覆盖/重叠
- 我怎么知道两条线是否重叠?
- 检查时间范围是否重叠,如果为真则触发错误
- 是否有一种有效的方法来测试字符串是否包含非重叠子字符串以匹配正则表达式数组
- 检测元素边界是否与父元素边界重叠