曜日の判定処理を2進数でやりたい

2019年11月3日

概要

プログラムを書いていて、曜日の判定処理をしたい時があるかと思います。
今回は、「判定したい曜日の情報をDBに保持しておき、そのDBの値を用いて今日が設定されている曜日に該当するか」という判定処理を実装してみたいと思います。

まず自分が思いついたのは、月曜日~日曜日の行を持つマスタテーブルを作成して判定したい曜日を格納すれば良いんじゃないかと考えました。
しかし、この方法には問題があります。

ちなみに、以下の様なテーブルを考えてました

Week_table(曜日テーブル)

WeekCD WeekName SortOrder UpdDate
1 月曜日 1 HHMMDD
2 火曜日 2 HHMMDD
3 水曜日 3 HHMMDD
4 木曜日 4 HHMMDD
5 金曜日 5 HHMMDD
6 土曜日 6 HHMMDD
7 日曜日 7 HHMMDD

DayOfWeek_Judge_table(判定したい曜日を格納するテーブル)

WeekCD UpdDate
2 HHMMDD
4 HHMMDD

まず、更新が大変ですし、プログラムで値を取り出すときに繰り返し処理が必要になったり扱いが面倒になります。

では、どのようなテーブルを設計すればスマートになるでしょうか。

自分なりの結論として、2進数で曜日の判定情報を保持すればテーブルに追加する行は1行で済み、追加するカラムは1つのみになります。

例えば、
月、火、水、木、金、土、日の土日を除外したい(=フラグを立てたい)ときは、以下の様に表現できます。
0:除外しない
1:除外

曜日 2進数表記 10進数表記
0000001 1
0000010 2
0000100 4
0001000 8
0010000 16
0100000 32
1000000 64

なので土日を除外するという表現は96(=1100000(2))と表現できます。
これなら、

項目名 フィールド名 サイズ
曜日判定 DayOfWeek int 4

という様なDBで値を管理して曜日判定をすることが可能になります。

論理積で該当曜日を判定したい

例えば、DBに月木金を除外する設定(=0011001(2))、10進数の25が格納されているとします。
プログラム側の処理で、今日の曜日を取得してきて今日が木曜日(=0001000(2))、つまり10進数で表現すると8だったとして、木曜日が除外設定されているかを判定するにはこの2つを論理積で演算してあげれば判定できます。

計算イメージ

判定したい曜日がDBに設定されている曜日に該当する例

曜日 2進数 10進数
月木金を除外するDBの設定値 0011001 25
判定したい曜日(木曜日) 0001000 8
論理積(AND演算) 0001000 8

SQLで記述すると、上記の論理積の演算は以下の様に表現できます。

SELECT (25 & 8) AS A;

とすると、以下の答えが返ってきます。

8

と結果が返ってきて、木曜日が除外設定されている曜日であるという判定ができます。

判定したい曜日がDBに登録されている除外設定曜日にい該当しない例

曜日 2進数 10進数
月水金を除外するDBの設定値 0010101 21
判定したい曜日(木曜日) 0001000 8
論理積(AND演算) 0001000 0

SQLで記述すると、上記の論理積の演算は以下の様に表現できます。

SELECT (21 & 8) AS A;

とすると、以下の答えが返ってきます。

0

C#の参考コード

先ほどはSQLでの判定の例を書きましたが、C#で判定しても同じような論理積演算で判定する事が可能です。

//月曜日と火曜日
var getuka = 3;
//2進数に変換
Console.WriteLine("月曜日と火曜日を表す10進数を2進数に変換");
Console.WriteLine(Convert.ToString(getuka, 2));
var bitGetuka = Convert.ToString(getuka, 2);
//判定したい曜日(月曜日)
var hanteiGtu = 1;
//論理積演算
Console.WriteLine("論理積演算");
Console.WriteLine(getuka & hanteiGtu);
var hanteiMoku = 8;
Console.WriteLine("木曜日を判定");
Console.WriteLine(getuka & hanteiMoku);
Console.WriteLine("判定結果のデータ型を確認");
Console.WriteLine((getuka & hanteiMoku).GetType().Name);