如何检查另一个日期时间持续时间中是否存在日期时间持续时间?

How to check a datetime duration exists in another datetime duration?

我正在开发一个 Rails 考试管理应用程序。

可以在一段时间内创建考试。

Exam 模型有字段 start_date:datetimeend_date:datetime

创建考试分为两步。在第一步中,将提供所有考试详细信息,包括 start_dateend_date

第二步我想列出所有与当前考试时间段有冲突的考试,以便用户选择是否继续。

示例:

当前考试:

Start date and time: "2015-02-23 10:30:00"

End date and time: "2015-02-23 13:30:00"

冲突的考试:

Start date and time: "2015-02-23 12:30:00"

End date and time: "2015-02-23 14:30:00"

怎么可能?

试试这个,通过其他考试 conf 对象 to overlaps 方法。它将 return 冲突的考试对象数组

conf_array = []
def overlaps(conf)
    conf_array << conf if  (start_date - conf.end_date) * (conf.start_date - end_date) >= 0
end

conf_array = []
def overlaps(conf)
    conf_array << conf if ((start_date..end_date).cover?(conf.start_date) || (start_date..end_date).cover?(conf.end_date))
end

conf_array = []
def overlaps(conf)
    conf_array << conf if ((start_date..end_date).include_with_range?conf.start_date || (start_date..end_date).include_with_range?conf.end_date )
end

如何创建名为 exam_time_range

的属性
def exam_time_range
  start_date..end_date
end

检查冲突的另一种方法

def time_conflict?(time)
  exam_time_range.cover?(time) || time.cover?(exam_time_range)
end

最后但同样重要的是,保持逻辑的方法

def list_all_conflicts
  Exam.find_each do |exam|
    if time_conflict?(exam.start_date..exam.end_date)
      exam
    end
  end
end

最简单的检查是否没有冲突,然后加上!。很明显,如果一个考试在另一个考试结束之后开始,或者在另一个考试开始之前结束。

我假设如果一个考试同时开始另一个考试结束则没有冲突,但如果这被认为是冲突,这只是一个简单的改变。我还假设没有时间旅行(即考试在开始之前结束)。

require 'time'

def conflict?(exam1, exam2)
  !(Time.parse(exam1.last)  <= Time.parse(exam2.first) ||
    Time.parse(exam1.first) >= Time.parse(exam2.last))
end

conflict?(["2015-02-23 10:30:00", "2015-02-23 13:30:00"],
          ["2015-02-23 12:30:00", "2015-02-23 14:30:00"])
  #=> true
conflict?(["2015-02-23 10:30:00", "2015-02-23 13:30:00"],
          ["2015-02-23 12:30:00", "2015-02-23 13:30:00"])
  #=> true
conflict?(["2015-02-23 10:30:00", "2015-02-23 12:30:00"],
          ["2015-02-23 12:30:00", "2015-02-23 13:30:00"])
  #=> false
conflict?(["2015-02-23 10:30:00", "2015-02-23 12:30:00"],
          ["2015-02-24 12:30:00", "2015-02-24 13:30:00"])
  #=> false

编辑: 想一想,由于采用了日期时间字符串格式,因此没有必要解析字符串。例如:

"2015-02-23 10:30:00" <= "2015-02-23 12:30:00"
  #=> true

我们有:

def conflict?(exam1, exam2)
  !(exam1.last <= exam2.first || exam1.first >= exam2.last)
end

conflict?(["2015-02-23 10:30:00", "2015-02-23 13:30:00"],
          ["2015-02-23 12:30:00", "2015-02-23 14:30:00"])
  #=> true
conflict?(["2015-02-23 10:30:00", "2015-02-23 12:30:00"],
          ["2015-02-23 12:30:00", "2015-02-23 13:30:00"])
  #=> false

为什么不在单个 AR 查询中进行呢?类似于下面的内容,但绝对可以写得更优雅。

# whatever u want
e = Exam.first 

# Where start between e.start , e.end
# Or end between e.start , e.end
# And != e
Exam.where('start_date between datetime(?) and datetime(?) 
OR end_date between datetime(?) and datetime(?)', 
e.start_date, e.end_date, e.start_date, e.end_date)
.where.not(id: e.id)