Как вычесть один временной интервал из другого в Ruby?

Мне нужно вычесть один временной интервал из другого.

Пример: timespan1 - с 1 января 2014 года по 15 января 2014 года. Timespan2 - с 5 января по 10 января. Я хотел бы получить что-то вроде:

timespan1 - timespan2 = 01/01 to 01/04 AND 01/11 to 01/15

Есть ли драгоценный камень, который я мог бы использовать для чего-то вроде этого? Если бы я хотел сделать это вручную, мне пришлось бы рассмотреть много случаев (временные интервалы перекрываются / не перекрываются, частично / полностью перекрываются и т. Д.). Если не драгоценный камень, возможно, идея алгоритма проще, чем рассмотрение всех этих случаев отдельно.?

2 ответа

Решение

Вы можете решить свой пример, используя обычные объекты Arrays of Date. Предполагая, что вы используете только дни, я считаю, что это будет работать очень хорошо в тех случаях, которые вас интересуют.

require 'date'

a = [* Date.new(2014,1,1) .. Date.new(2014,1,15)]
b = [* Date.new(2014,1,5) .. Date.new(2014,1,10)]

diff = a - b

diff.each { |date| puts date.strftime('%d %B %Y') }

# Output:
# 01 January 2014
# 02 January 2014
# 03 January 2014
# 04 January 2014
# 11 January 2014
# 12 January 2014
# 13 January 2014
# 14 January 2014
# 15 January 2014

Предполагать

r1 = (f1..l1)
r2 = (f2..l2)

где f1, l1, f2 а также l2 являются объектами даты (возможно, преобразованными из строк) или любыми другими объектами, которые могут формировать диапазон. Я предполагаю, что вы хотите построить массив, который включает в себя все элементы, охватываемые r1 которые не покрыты r2, Обратите внимание, что результат не обязательно может быть выражен в виде диапазона, так как в некоторых случаях элементы, охватываемые r1 но не r2 не являются смежными, как когда r1 = (1..6) а также r2 = (3..4)где результат [1,2,5,6],

Код

Мы можем вычислить нужный массив непосредственно из конечных точек двух заданных диапазонов. Есть шесть случаев для рассмотрения, которые охватываются case заявление.

def range_difference(r1, r2)
  f1, l1 = r1.first, r1.last
  f2, l2 = r2.first, r2.last
  case
  when l2 < f1
    (f1..l1).to_a
  when f2 <= f1 && f1 <= l2 && l2 < l1
    (l2+1..l1).to_a
  when f2 <= f1 && l1 <= l2
    []
  when f1 < f2 && f2 < l1 && l2 < l1
    (f1..f2-1).to_a + (l2+1..l1).to_a
  when f1 < f2 && f2 <= l1 && l2 >= l1
    (f1..f2-1).to_a
  else # f2 > l1
    (f1..l1).to_a
  end
end

Примеры

range_difference((5..10),(2..7))
  #=> [8, 9, 10]
range_difference((5..10),(2..10))
  #=> []
range_difference((5..10),(6..8))
  #=> [5, 9, 10]
range_difference((5..10),(6..10))
  #=> [5]
range_difference((5..10),(7..12))
  #=> [5, 6]
range_difference((5..10),(10..12))
  #=> [5, 6, 7, 8, 9]
range_difference((5..10),(11..12))
  #=> [5, 6, 7, 8, 9, 10]
Другие вопросы по тегам