Как вычесть один временной интервал из другого в 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]