特定の日時から曜日を算出する
MEMORANDUM
数学のツェラー (Zeller) の公式を用いて日にちから曜日を求める方法と、どの年が閏年にあたるかを調べる方法について、整理しておくことにしました。
特定の日時から曜日を算出する
■ はじめに
ここの備忘録は、あくまでも走り書き程度のメモ的なものですので気をつけてください。
そのままでもちゃんと動くもの、手を加えないとだめなものなど、未完成レベルのコードです。ので、そのまま引用してしまうなど、プログラムを理解する知識のない方は利用しないでくださいね。
■ 概要
今回は Zeller の公式というものを使って特定の日時から曜日を算出してみました。曜日は、0 から 6 までがそれぞれ日曜日から土曜日に対応した値として取得できます。
■ 閏年の規則
とりあえず、グレゴリオ暦では次の規則で閏年を置くことになっているようです。
- 基本的に 4 で割り切れる年は閏年とする。
- ただし、100 で割り切れる年は閏年とはしない。
- ただし、400 で割り切れる年は閏年とする。
…、とこれは余談ですけど。
■ Zeller の公式
曜日 W を求めたい日付を YYyy 年 mm 月 dd 日としたとき、次の式を用いて曜日を算出することが出来るようです。
W = [ YY/4 ] - 2YY + [ yy/4 ] + yy + [ 26(mm + 1)/10] + dd (mod 7)
ここで [ ] はガウス記号という算術記号で、その値を超えない最大の整数という意味です。
この計算式から求められた値は、次のような感じで曜日に対応します。
W の値 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
対応する曜日 | 日 | 月 | 火 | 水 | 木 | 金 | 土 |
■ C++ コードと注釈
/*
year 年 month 月 day 日の曜日を取得します。
0 … 日曜日 / 1 … 月曜日 / 2 … 火曜日 / … / 6 … 土曜日
*/
int zeller(int year, int month, int day)
{
// month が 1 または 2 である場合は微調整をします。
if (month == 1 || month == 2)
{
// 1月は前年の13月、2月は前年の14月とします。
year--;
month += 12;
}
// 地球の公転周期の有理数近似 365 + 1/4 - 1/100 + 1/400 とあわせて、また、小数点演算を整数かすることで 30 日と 31 日の誤差を吸収するらしいです。
// 年を上位 (yH) と下位 (yL) とに分離します。
int yH = int(year/100);
int yL = year - (yH * 100);
// Zeller の公式を用いて week を計算します。
int week = (yH >> 2) - 2 * yH + (yL >> 2) + yL + int((month + 1) * 2.6) + day;
return week % 7;
}