Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: intersection between two ranges

Tags:

date

range

ruby

In ruby, given two date ranges, I want the range that represents the intersection of the two date ranges, or nil if no intersection. For example:

(Date.new(2011,1,1)..Date.new(2011,1,15)) & (Date.new(2011,1,10)..Date.new(2011,2,15))
=> Mon, 10 Jan 2011..Sat, 15 Jan 2011

Edit: Should have said that I want it to work for DateTime as well, so interval can be down to mins and secs:

(DateTime.new(2011,1,1,22,45)..Date.new(2011,2,15)) & (Date.new(2011,1,1)..Date.new(2011,2,15))
=> Sat, 01 Jan 2011 22:45:00 +0000..Tue, 15 Feb 2011
like image 521
jjnevis Avatar asked Dec 07 '11 11:12

jjnevis


2 Answers

require 'date'

class Range
  def intersection(other)
    return nil if (self.max < other.begin or other.max < self.begin) 
    [self.begin, other.begin].max..[self.max, other.max].min
  end
  alias_method :&, :intersection
end

p (Date.new(2011,1,1)..Date.new(2011,1,15)) & (Date.new(2011,1,10)..Date.new(2011,2,15))
#<Date: 2011-01-10 ((2455572j,0s,0n),+0s,2299161j)>..#<Date: 2011-01-15 ((2455577j,0s,0n),+0s,2299161j)>
like image 55
steenslag Avatar answered Sep 18 '22 16:09

steenslag


You can try this to get a range representing intersection

range1 = Date.new(2011,12,1)..Date.new(2011,12,10)
range2 = Date.new(2011,12,4)..Date.new(2011,12,12)

inters = range1.to_a & range2.to_a

intersected_range = inters.min..inters.max

Converting your example:

class Range  
  def intersection(other)  
    raise ArgumentError, 'value must be a Range' unless other.kind_of?(Range)  

    inters = self.to_a & other.to_a

    inters.empty? ? nil : inters.min..inters.max 
  end  

  alias_method :&, :intersection  
end
like image 30
Aliaksei Kliuchnikau Avatar answered Sep 19 '22 16:09

Aliaksei Kliuchnikau