LoginSignup
14
13

More than 5 years have passed since last update.

日付をまたぐ場合も考慮した時間内判定

Posted at

問題

現在時刻 $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 になっちゃうようなクソシステムに是非。

14
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
13