🎉

Rubyで2つの時間が重なっているか比較を行う方法

2022/11/24に公開

Rubyで2つの時間が重なっているか比較を行う方法

やりたいこと

時間A(9:00〜11:00)と、時間B(10:00〜12:00)が少しでも重なっているか、boolで取得したい。

結論

まずは結論から。
冗長に書きます。適宜短くしてください。

# 比較したい時間たちを、INTに変換
time_a_start = time_to_int('9:00')
time_a_end   = time_to_int('11:00')
time_b_start = time_to_int('10:00')
time_b_end   = time_to_int('12:00')

# 範囲オブジェクトに成形
time_a = time_a_start..time_a_end
time_b = time_b_start..time_b_end

# 重なりの結果を、boolで取得

# cover?が使えるなら
(time_a).cover?(time_b) # => true

# 使えないなら
range_include?(time_a, time_b) # => true


# 時間をINT型に変換するメソッド
def time_to_int(time)
  if time.class == String
    time.gsub(':','').to_i
  else
    time.strftime('%H%M').to_i
  end
end

# 2つの範囲オブジェクトの重なりをチェックするメソッド
def range_include?(r1, r2)
  (r1.max >= r2.min && r2.max >= r1.min) ? true:false
end

注意点

タイムゾーンには気をつけましょう(n敗)

解説

先ほど使ったメソッドの解説

時間をINT型に変換するメソッド

def time_to_int(time)
  if time.class == String
    time.gsub(':','').to_i
  else
    time.strftime('%H%M').to_i
  end
end

Stringオブジェクトでも、TIMEオブジェクトでもINTに変換できるようにしています。
冗長ですが、そろってないことも多かったので。

time_to_int('10:30')  #=> 1030
time_to_int(Time.now) #=> 1030

時間は必ず0:00 -> 23:59 と増えていくので、INTにしちゃえばRangeに変換して、簡単に比較できるということです。

2つの範囲オブジェクトの重なりをチェックするメソッド

cover? メソッドが使えるなら、そのまま使えばOKです。
https://docs.ruby-lang.org/ja/latest/method/Range/i/cover=3f.html

使えない場合は、下記の記事で解説されている方法がオススメです。
https://qiita.com/namarin/items/467abd5a4d37ef8feacc

# 2つの範囲オブジェクトの重なりをチェックするメソッド
def range_include?(r1, r2)
  (r1.max >= r2.min && r2.max >= r1.min) ? true:false
end

以上

書いた経緯

二つの時間範囲が重なっているかをチェックしたくて調べた際、ピンポイントに解決してくれる記事がみあたらなかったので、とりあえず忘備録として残します。

Discussion