問題
現在時刻 $Now$ が 開始時刻 $Start$ と 終了時刻 $End$ の範囲内かを判定したい。
ただし、開始時刻と終了時刻が夜中の0時をまたぐ場合があり、この場合は $End < Start$ ということがあり得る。
どのように判定すればよいか?
ただし、等号については、
- $Start = Now$ つまり開始時刻ピッタシは $\textrm{true}$
- $Now = End$ つまり終了時刻ピッタシは $\textrm{false}$
- $Start = End$ つまり開始時刻と終了時刻が一致している場合は 24 時間 OK
としたい。
if 文を使った答え
素朴にはまず $Start <= End$ か $End < Start$ かで場合分けをし、
- $Start \le End$ だった場合 → $Start \le Now$ かつ $Now < End$ だったら $\textrm{true}$
- $End < Start$ だった場合 → $Now < End$ または $Start \le Now$ だったら $\textrm{true}$
とすれば良い。
Ruby
def time_between? s, n, e
if s <= e
s <= n && n < e
else
n < e || s <= n
end
end
JavaScript
function timeBetween(s, n, e) {
if (s <= e)
return s <= n && n < e;
else
return n < e || s <= n;
}
Scala
import org.joda.time.LocalTime
object Time {
def timeBetween(s: LocalTime, n: LocalTime, e: LocalTime): Boolean = {
if (s.compareTo(e) <= 0) // s <= e i.e. s - e <= 0
s.compareTo(n) <= 0 && n.compareTo(e) < 0
else
n.compareTo(e) < 0 || s.compateTo(n) <= 0
}
}
xor を使った答え
$\textrm{xor}$(排他的論理和)を使うともう少しスマートに書くことができる。
$\textrm{xor}$ は、$A , \textrm{xor} , B , \textrm{xor} , C$ という式において、どこかの符号が反転したら結果の符号も反転する、という性質を持つ。
# | $A: s \le n$ | $B: n < e$ | $ C: s < e$ | $A \oplus B \oplus C$ | 備考 |
---|---|---|---|---|---|
1 | $\textrm{true}$ | $\textrm{true}$ | $\textrm{true}$ | $\textrm{true}$ | 開催中 |
2 | $\textrm{false}$ | $\textrm{true}$ | $\textrm{true}$ | $\textrm{false}$ | 開始前 |
3 | $\textrm{true}$ | $\textrm{false}$ | $\textrm{true}$ | $\textrm{false}$ | 終了後 |
4 | $\textrm{true}$ | $\textrm{false}$ | $\textrm{false}$ | $\textrm{true}$ | 日をまたぐ場合で、現在まだ日をまたいでいない |
5 | $\textrm{false}$ | $\textrm{true}$ | $\textrm{false}$ | $\textrm{true}$ | 日をまたぐ場合で、既に日をまたいでいる |
6 | $\textrm{false}$ | $\textrm{false}$ | $\textrm{false}$ | $\textrm{false}$ | 日をまたぐ場合で、終了後、開始前 |
Ruby
def time_between? s, n, e
(s <= n) ^ (n < e) ^ (s < e)
end
JavaScript
function timeBetween(s, n, e) {
return !!(s <= n ^ n < e ^ s < e);
}
Scala
import org.joda.time.LocalTime
object Time {
def timeBetween(s: LocalTime, n: LocalTime, e: LocalTime): Boolean = {
s.compareTo(n) <= 0 ^ n.compareTo(e) < 0 ^ s.compareTo(e) < 0
}
}
開始時刻 0 〜 23時、終了時刻 1 〜 24 時 とかいう制限をかけておいて DB 上では time 型で endTime = 0:00:00 になっちゃうようなクソシステムに是非。