TL;DR
delta = 10.minute
schedule = %w[10:00 12:00 14:00 16:00 18:00]
time_ranges = schedule.map do |t|
(Time.parse(t) - delta)..(Time.parse(t) + delta)
end
case Time.now
when *time_ranges
p "範囲内です"
else
p "範囲外でござる"
end
経緯
とある要望で現在の時間が指定の時間帯に含まれるかをチェックする必要がありました。
例:
現在時刻が10:00、12:00、14:00、16:00、18:00の前後10分の区間内に含むかを判断せよ
大人しくIF文を組むのもいいですが、上記スケジュールもいつか変数になると考え、拡張性のある上手い書き方があるか考えました。
解説
レガシーなbetween?
SQLもそうですが、含むか含まないかを判断するには、Between
が王道でした。
もちろん、RubyにもBetweenができますが、下記のように、1つのBetweenは1つの区間しか対応できません。
Time.now.between?(Time.parse('10:00'), Time.parse('18:00'))
case..when
記法の活用
Rubyのcase..when
記法は、以下のメリットがあります。
- 複数条件が書けます。 Eg:
when 1,3,5,7
- 範囲(Range)に対応します。 Eg:
when 1..5
- 条件は配列の展開式にも対応します。 Eg:
when *[5,10,15]
上記仕様を利用すれば、簡単に連続でない不特定の区間を判定できます。
# まずはRangeリストを組むこと
# Railsではない時
require 'time'
delta = 10 * 60
# Railsの時
delta = 10.minute
time_ranges = %w[10:00 12:00 14:00 16:00 18:00].map do |t|
(Time.parse(t) - delta)..(Time.parse(t) + delta)
# <含む...含まない> にしたい時は `...` を使うこと
end
=> [2021-07-09 09:50:00 +0900..2021-07-09 10:10:00 +0900,
2021-07-09 11:50:00 +0900..2021-07-09 12:10:00 +0900,
2021-07-09 13:50:00 +0900..2021-07-09 14:10:00 +0900,
2021-07-09 15:50:00 +0900..2021-07-09 16:10:00 +0900,
2021-07-09 17:50:00 +0900..2021-07-09 18:10:00 +0900]
# あとは上記Rangeリストを `case..when` 文に組み込むこと
case Time.now
when *time_range_list
p "範囲内です"
else
p "範囲外でござる"
end