ユリウス日(Julian Date, JD)は主に天文学で使われている 日時の表現でBC4713/1/1 12:00(正午)を起点とした通日。 小数点以下で時刻を表す。
例: 1970/01/01 00:00 のユリウス日 == 2440587.5
準ユリウス日(修正ユリウス日ともいう。Modified Julian Date, MJD)は ユリウス日から240000.5を引いたもの。起点の日付はAD1858/11/17になるが これはきりのよい数を引いた副作用でとくに意味はない。
最近の日付しか登場しない問題を解くときには準ユリウス日を使うほうが便利である。 ユリウス日(純正の)は値が無意味に大きくなり、 また厳密に計算すると同じ日の正午に値が変わってしまう。
準ユリウス日を算出する学術的な公式は次のとおり。
MJD == [365.2524y] + [30.59(m-2)] + d - 678912
(y年m月d日、グレゴリオ暦の範囲。[n]:n整数部。m = 1,2 のときは m +=12, --y として計算)
グレゴリオ暦の開始は国によって異なるので注意。 ユリウス日を計算する単純なプログラムはおそらくグレゴリオ暦の範囲でしか 正しくない。このページで紹介するものもそうである。
開始 | その前日の日付 | |
---|---|---|
ヨーロッパ諸国 | 1582/10/15 | 1582/10/4 |
アメリカ | 1752/9/14 | 1752/9/2 |
日本 | 1873/1/1(明治6) | 明治5/12/2 |
注: 日本は天保暦(旧暦、太陽太陰暦)からの移行も兼ねている。
整数計算だけを使ったプログラムを紹介しよう。 『プログラム書法』的な読みやすさはあえて犠牲にしている。 読みやすさを優先したいのなら浮動小数を使って学術的な公式どおりに 計算すればよろしい。
static const int m2yd[13] = { 0, 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275 }; long ymd2mjd(int y, int m, int d) { if (m < 3) { --y; } return (long)y * 365 + y / 4 - y / 100 + y / 400 + m2yd[m] + d - 1 - 678881; }
とくに公式はないので地道に逆変換するしかない。ここでは 整数計算はもちろんのこととして、さらにループを一切使わない プログラムを紹介する。わかってる、これも読みやすいとはいえない。 ループを使って年ごと・月ごとの日数を 引いていくロジックの方がずっとわかりやすいだろう。しかしそんなプログラムなら そこらにいくらでも転がっている。新たにこのページに載せる意味がない。
static const char yd2m[366] = { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, }; /* m2yd[] も使用するので必要ならここで定義する */ void mjd2ymd(long j, int *py, int *pm, int *pd) { static const int t[] = { 0, 1, 2, 3, 3 }; int q; int y, m; j += 678881; q = (int)(j / 146097); /* 400年単位の処理 */ j -= q * 146097L; y = q * 400; q = t[j / 36524]; /* 100年単位の処理 */ j -= q * 36524L; y += q * 100; q = (int)(j / 1461); /* 4年単位の処理 */ j -= q * 1461; y += q * 4; q = t[j / 365]; /* 1年単位の処理 */ j -= q * 365; y += q; /* j には年通日が残っている */ m = yd2m[j]; if (m < 3) { ++y; } *py = y; *pm = m; *pd = (int)j - m2yd[m] + 1; }
ちなみに曜日の判定は次のようにしてできる。
if ((mjd + 3) % 7 == 0) { /* 日曜日 */ }
一方を変更して計算ボタンを押す。
日付と日付の差を計算したり、ある日付の±N日後を計算できるようにする 方がおもしろいかな。