めあとるーむ記録帳

なんか書く

第n何曜日を計算する

いくつかの祝日とかゴミ捨てとかはmmddであらわされず、基本的に特定の月(あるいはすべての月)の特定の回数目の曜日に行うと決まっている。

祝日はまあその手のAPIサービスを使うとして、ゴミ捨てなどをデータベースに入れるにはどうしたものかと思いつつ、とりあえず毎月特定の日に起こるイベントをまとめたテーブルを作ることにした。

毎週起こるイベント(燃えるゴミの日とか)はエブリウィークのテーブルにしつつ、毎月第一水曜日の燃えないゴミの日などを管理するという感じ。

カレンダーとかリマインダーのデータベース設計したことないんだけど何かいい資料があるなら教えて。

とりあえず第n何曜日の定義はその月の何回目何曜日かということで、抽象的すぎるから具体的にみんな大好き月曜日で考える。

第1月曜日その月の1日~7日の中にある。1日が火曜日なら7日が月曜日、1日が日曜日なら2日が月曜日。

同様に第2月曜日は8日~14日の中にある。あるいは第1月曜日の日付を把握できたのであればその日付に7を足せばいい。後は同様に考えればいい。

以上からまず計算に必要な要素は

  • その月のどこかの日付と曜日(基本は第1日が計算しやすいと思われる)

さえあればとりあえず計算できる。

MySQLなら特定の日付の曜日を取得する関数はDAYOFWEEK(日曜日はじめ)とかWEEKDAY(月曜日はじめ)があるのでそれを使えばとれる。

mysql> SELECT WEEKDAY(yyyymm01);

これの答えがyyyy年mm月1日の曜日である。WEEKDAYの月曜日は0で返ってくるので、7進数で考えて、7からこれの答えを引くと月曜日までの日数が分かる。

もうちょっと具体的に2017年1月で考えて、

mysql> SELECT WEEKDAY(20170101);
+-------------------+
| WEEKDAY(20170101) |
+-------------------+
|                 6 |
+-------------------+
1 row in set (0.03 sec)

1月1日は6=日曜日だ。では2017年1月の第1月曜日は

mysql> SELECT 7-WEEKDAY(20170101);
+---------------------+
| 7-WEEKDAY(20170101) |
+---------------------+
|                   1 |
+---------------------+
1 row in set (0.00 sec)

つまり1日後、1月2日ということになる。

mysql> SELECT 20170101+(7-WEEKDAY(20170101));
+--------------------------------+
| 20170101+(7-WEEKDAY(20170101)) |
+--------------------------------+
|                       20170102 |
+--------------------------------+
1 row in set (0.05 sec)

まあこうでもいい。週ごとに以下数字から引けて、1日の日付に足せばいい。

func sun mon tue wed thu fri sat
WEEKDAY() 6 7 8 9 10 11 12

あるいは足し算で出てきた結果と足す形にした方がいいかもしれない。そこは適宜数字を変えるとして。

そして第2曜日以降は各々の数字に7を足す。第2月曜日なら7+7という感じ。

この辺りは関数化して求められるようにするのが理想だろう。たぶん。

すでにあったら申し訳ねえが教えてくだされ


追記

なんかDAYOFWEEKだとうまくいかなかったから削除。理屈は同じだけど考えるのが面倒なのでやりたい人は勝手にどうぞ