我正在构建可用性日历。这是一个月视图,天几乎是一个布尔值,它们可以是可用的,也可以是不可用的。有多种产品"可以存在于日历上。相对简单。
我存储这些"可用性范围"作为一个尽可能简洁的对象数组。因此,单个产品的可能数据集如下所示:
[
{
"startDate": "2016-11-08",
"endDate": "2016-11-08"
},
{
"startDate": "2016-11-11",
"endDate": "2016-11-14"
},
{
"startDate": "2016-11-20",
"endDate": "2016-11-22"
}
]
用户界面与此日历非常相似:
真正的麻烦来自用户更新其可用性。他们可以选择更新所有"或者"更新一个"。例如,如果房间1在1月5日已经不可用,并且用户现在想要从1月1日到1月10日使所有房间都不可用,我需要从阵列中移除1月1日房间1对象,因为它与新的重叠数据。
此外,我想合并任何连续的时间跨度,例如:
[
{
"startDate": "2016-11-08",
"endDate": "2016-11-08"
},
{
"startDate": "2016-11-09",
"endDate": "2016-11-09"
},
]
应该合并到:
[
{
"startDate": "2016-11-08",
"endDate": "2016-11-09"
},
]
我意识到这是一个相对复杂的问题,但肯定必须有一个预先存在的解决方案,或者至少类似的东西?
我可以访问momentJs。
答案 0 :(得分:1)
我不知道这是否是最快方法,但一个好的起点是利用Array.sort
按日期规范化数据,以便任何连续日期将彼此相邻,然后使用简单的数组遍历来合并连续日期。
下面的示例使用sort
数组遍历。
let states = [
{
"startDate": "2016-11-08",
"endDate": "2016-11-08"
},
{
"startDate": "2016-11-11",
"endDate": "2016-11-14"
},
{
"startDate": "2016-11-20",
"endDate": "2016-11-22"
},
{
"startDate": "2016-11-15",
"endDate": "2016-11-19"
},
];
console.log('Started With:', states);
let sorted_states = states.sort(function(a,b){
return (new Date(a.startDate)) - (new Date(b.startDate))
});
// simple array traversal method
for (let i = sorted_states.length - 1; i--;){
let current = sorted_states[i];
let next = sorted_states[i+1];
interval = ((new Date(next.startDate) - new Date(current.endDate)));
if (interval <= (1000 * 60 * 60 * 24)){ // one day
newEntry = {
startDate : current.startDate,
endDate : next.endDate,
};
sorted_states[i] = newEntry;
sorted_states.splice(i+1, 1); // delete coalesced entry
}
}
console.log('Ended With:', sorted_states)
&#13;
答案 1 :(得分:0)
您可以使用两个对象作为开始和结束日期的哈希表,并使用使用时刻获取明天的日期,并查看日期是否为开始日期。
然后更新对象,从开始和结束对象中删除,然后重新注册。
此提案适用于未分类的数据。
function getTomorrow(day) {
return moment(day).add(1, 'days').format("YYYY-MM-DD");
}
var array = [{ startDate: "2016-11-08", endDate: "2016-11-08" }, { startDate: "2016-11-09", endDate: "2016-11-09" }, { startDate: "2016-12-02", endDate: "2016-12-02" }, { startDate: "2016-12-03", endDate: "2016-12-03" }, { startDate: "2016-12-01", endDate: "2016-12-01" }, { startDate: "2016-12-04", endDate: "2016-12-04" }, ],
start = {},
end = {},
result;
array.forEach(function (object) {
start[object.startDate] = object;
end[object.endDate] = object;
});
Object.keys(end).forEach(function (today) {
var tomorrow = getTomorrow(today);
if (start[tomorrow]) {
end[today].endDate = start[tomorrow].endDate;
end[tomorrow] = end[today];
delete end[today];
delete start[tomorrow];
}
});
result = Object.keys(start).map(function (k) {
return start[k];
});
console.log(result);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.2/moment.min.js"></script>
&#13;
答案 2 :(得分:0)
立即使用isbetween
方法。
设计:在用户选择开始日期和结束日期后,使用他的开始日期并将其与日期数组(arr)中的每个条目进行比较,如果某个条目的开始日期在用户选择的范围内,则将其删除。在迭代完所有条目后,添加用户选择范围到arr
userSdate="2016-11-08"
userEdate="2016-11-09"
for(i=0;i<arr.length;i++)
{
tmpSdate = arr[i].startDate;
tmpEdate = arr[i].endDate;
console.log( tmpSdate + " : " + tmpEdate );
isIn=moment(tmpSdate ).isBetween(userSdate,userEdate, null, '[]'); //note:[] means inclusive range
if(isIn)
{
delete(arr[i]);//remove arr[i]
}
}
arr.push({ "startDate": userSdate, "endDate" : userEdate});
由于删除不重新索引和更新长度属性,您可能需要重新索引它,尽管这不是强制性的。
请注意,我假设没有&#34;范围交叉&#34; (当范围A的开始完全位于范围B内但不是它(A)结束时),见下文
1 1
A-2------2----3----3--4----------4-----B (no range crossing)
C------D E----F G----------H
A--2------------------2--4--------------4---B (range crossing)
C-------3----------D G--3-----------H
E----------------F
答案 3 :(得分:0)
这是一个函数(ES6),可用于合并两个数组,每个数组包含句点。我在下面将它应用于一些示例数据,这些数据比您提供的数据更加扩展,因此它涵盖了几种重叠和邻接的情况:
function mergePeriods(a, b) {
return a.concat(b)
.sort( (a, b) => a.startDate.localeCompare(b.startDate) )
.reduce( ([res, end], p) =>
new Date(p.startDate).getTime()<=new Date(end).getTime()+90000000
? p.endDate > end
? [res, res[res.length-1].endDate = p.endDate]
: [res, end]
: [res.concat(p), p.endDate],
[[], '1970-01-01'])[0];
}
// sample data
var unavailable1 = [
{
"startDate": "2016-11-08",
"endDate": "2016-11-08"
},
{
"startDate": "2016-11-11",
"endDate": "2016-11-14"
},
{
"startDate": "2016-11-20",
"endDate": "2016-11-22"
},
{
"startDate": "2016-11-27",
"endDate": "2016-11-27"
},
{
"startDate": "2016-11-29",
"endDate": "2016-11-29"
}
];
var unavailable2 = [
{
"startDate": "2016-11-09",
"endDate": "2016-11-09"
},
{
"startDate": "2016-11-12",
"endDate": "2016-11-15"
},
{
"startDate": "2016-11-18",
"endDate": "2016-11-21"
},
{
"startDate": "2016-11-26",
"endDate": "2016-11-28"
}
];
// merge the sample data
var res = mergePeriods(unavailable1, unavailable2);
console.log(res);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
作为第一步,两个数组通过增加开始日期进行连接和排序。
然后在该数组上调用reduce
,其起始值(对于累加器)等于:
[[], '1970-01-01']
这一对包含将被累积到最终结果的数组(它开始为空),以及最后遇到的endDate
日期,它被设置为很久以前的时间。
此对在reduce
回调中作为[res, end]
收到,并且数组中的当前元素名为p
。然后进行一些比较以检测句点p
与end
的关系。如果重叠是邻接,则更新(扩展)当前结果中的前一个元素以匹配p.endDate
,这也将成为下一次迭代中end
的新值。
如果上一期间完全包含p
,则会被忽略,[res, end]
会保留原样。
如果句点p
与前一个句点不相交,则会将其与结果(concat
)连接,end
设置为此p.endDate
。< / p>
当结果以这种方式组合并且reduce
返回时,我们不再对最新的结束日期感兴趣,而只对数组进行解释,这解释了最终的[0]
。
值90000000表示25小时内的毫秒数。这是为了检测两个周期是否相邻。额外1小时不会受到伤害,并且可以很好地处理一夜之间的DST变化。也可以使用momentjs
完成此操作,但这在普通JavaScript中也不麻烦。