例子

business_hours['monday'] = [800..1200, 1300..1700]
business_hours['tuesday'] = [900..1100, 1300..1700]


然后我有一堆事件占据了其中的一些时间间隔,例如
event = { start_at: somedatetime, end_at: somedatetime }

在从某个日期到某个日期的事件之间迭代,我创建了另一个数组
busy_hours['monday'] = [800..830, 1400..1415]


现在我的挑战是
创建包含营业时间减去营业时间的可用时间数组
available_hours = business_hours - busy_hours
给定一定的持续时间,比如30分钟,找出可用的时间段。在上面的示例中,这样的方法将返回
available_slots['monday'] = [830..900, 845..915, 900..930, and so on]
它不是以15分钟为增量检查指定时间段的可用小时数。
谢谢你的帮助!

最佳答案

我认为这是一个比特领域的工作。不幸的是,这个解决方案将依赖于神奇的数字、转换帮助程序和相当多的二进制逻辑,所以它不会很漂亮。但它会起作用并且非常有效。
这就是我解决问题的方法:
把你的日子分成合理的时间间隔。我将按照您的示例,将每个15分钟的时间块视为一个时间块(主要是因为它使示例保持简单)。然后以十六进制数字表示每小时的可用性。
例子:
0xF=0x1111=>整小时可用。
0xC=0x1100=>上半小时可用。
把其中的24串在一起代表一天。如果您可以确定不会发生超出范围的事件,则可以减少。这个例子继续假设24小时。
从这一点开始,我把长十六进制数分成几个字以便于阅读
假设一天从00:00到23:59business_hours['monday'] = 0x0000 0000 FFFF 0FFF F000 0000
为了让你的工作时间变得忙碌,你可以用类似的格式存储事件,并且把它们放在一起。
Exmample:

event_a = 0x0000 0000 00F0 0000 0000 0000 # 10:00 - 11:00
event_b = 0x0000 0000 0000 07F8 0000 0000 # 13:15 - 15:15

busy_hours = event_a & event_b

从繁忙时间和工作时间,您可以获得可用时间:
可用时间=营业时间和(忙碌时间^0xffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff)
异或(^)本质上将忙时转换为不忙时。与“不忙”和“营业”时间相比,我们可以获得一天中的可用时间。
这个方案还使得比较许多人的可用时间变得简单。
all_available_hours = person_a_available_hours & person_b_available_hours & person_c_available_hours

然后找到一个适合可用时间的时间段。你需要这样做:
将你的时间长度转换成一个类似的十六进制数字,即一小时,其中一个代表时间段将覆盖的该小时的所有时间段。下一步右移数字,这样就没有尾随的0了。
例子胜于解释:
0x1=>15分钟,0x3=>半小时,0x7=>45分钟,0xF=>整小时,…0xFF=>2小时等。
一旦你做到了这一点:
acceptable_times =[]
(0 .. 24 * 4 - (#of time chunks time slot)).each do |i|
  acceptable_times.unshift(time_slot_in_hex) if available_hours & (time_slot_in_hex << i) == time_slot_in_hex << i
end

高端市场有点混乱。所以让我们多看一点。我们不想转移太多次,否则我们会在频谱的早期得到假阳性。
24 * 4一天中24小时,每小时用4位表示。
- (#of time chunks in time slot)在我们寻找的时间段内,每15分钟减去1张支票。这个值可以通过(Math.log(time_slot_in_hex)/Math.log(2)).floor + 1找到。
它从一天结束时开始,检查每个时间段,在每次迭代中提前一个时间段(本例中为15分钟)。如果时间段可用,则将其添加到可接受时间的开始处。因此,当流程完成时,可接受的时间按发生顺序排序。
最酷的是,这个实现允许时间段合并,这样你的与会者可以在他们的一天中有一个繁忙的时间段,将你正在寻找的时间段平分为一个休息时间段,否则他们可能会很忙。
这取决于你写的帮助函数,在一个范围数组(即:[800..1200,1300..1700])和十六进制表示之间转换。最好的方法是将行为封装在对象中并使用自定义访问器方法。然后使用相同的对象来表示天、事件、繁忙时间等。此方案中唯一没有内置的内容是如何安排事件,以便它们可以跨越天的边界。

10-06 07:33