#include long greg2jd(int year, int month, int day); void jd2greg(long jd, int* year, int* month, int* day); int main() { long jd; /* ユリウス日 */ int year, month, day; /* 年・月・日 */ int y, m, d; /* これらは返り値用 */ year = -4713; month = 11; day = 24; /* これがユリウス日 0 の日 */ printf("このテストはマシンによっては少々時間がかかります. "); printf("「:」が約 365 個印字されるまでお待ちください. "); printf("エラーメッセージが出力されなければ成功です.\n"); for (jd = 0; jd < 3652425L; jd++) { int isleap; static char days[2][13] = { { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; if (greg2jd(year, month, day) != jd) { /* greg2jd() のテスト */ printf("error: %ld\n", jd); } jd2greg(jd, &y, &m, &d); if (year != y || month != m || day != d) { /* jd2greg() のテスト */ printf("error: %ld\n", jd); } isleap = !(year % 4) && year % 100 || !(year % 400); /* 閏年? */ if (++day > days[isleap][month]) { /* year, month, day を翌日に変更 */ day = 1; month++; if (month == 13) { month = 1; year++; } } if (jd % 10000 == 9999) { /* 途中のメッセージ */ printf(":"); fflush(stdout); } } printf("\n"); printf("テストは完了しました. "); printf("%d 年 %02d 月 %02d 日までチェックしました.\n", y, m, d); return 0; } /****************************************************************************** 【関数名】 greg2jd() 【機 能】 グレゴリウス暦からユリウス日への換算。 【引 数】 年、月、日。 【注意0】 ここでいうグレゴリウス暦とは、現行のグレゴリウス暦をその実施以前に までさかのぼって延長したものである。 【注意1】 紀元前の年の呼び方は、1 年の前年を 0 年とする天文学上の規約に従う。 引数は -4713 年 11 月 24 日(ユリウス日 0 の日)以降、桁あふれが 生じる直前まで有効である。実際には -4800 年 03 月 01 日以降に対し 正しいユリウス日を返すと思うが、あまり意味がないだろう。 【注意2】 最初に 4800 を足すのは閏年か平年かを変えずに考えるべき全ての年を正 にするため。最後の 32045 は“魔法の数”。 【注意3】 Zeller の公式の変形である。 ******************************************************************************/ long greg2jd(int year, int month, int day) { year += 4800; if (month < 3) { year--; month += 12; } return 365L * year + year / 4 - year / 100 + year / 400 \ + (153 * month - 457) / 5 + day - 32045; } /****************************************************************************** 【関数名】 jd2greg() 【機 能】 ユリウス日からグレゴリウス暦への換算。 【引 数】 ユリウス日、年・月・日を格納するアドレス。 【注意0】 ここでいうグレゴリウス暦とは、現行のグレゴリウス暦をその実施以前に までさかのぼって延長したものである。 【注意1】 紀元前の年の数え方は、紀元元年の前年を紀元 0 年とする天文学上の規約 に従う。引数のユリウス日は 0 以上、桁あふれが生じる直前まで有効で ある。実際にはもう少し前の、ユリウス日が負の日から使えると思うが、 あまり意味がないだろう。 【注意2】 最初の 32045, 最後の 4800 については greg2jd() の注意を参照のこと。 【注意3】 greg2jd() の“自然”な“逆関数”である。特別なことはしていない。 ******************************************************************************/ void jd2greg(long jd, int* year, int* month, int* day) { int century; /* (十進の)「年」を右に二桁だけシフトしたもの */ int y, m; /* 年、月を格納する一時変数 */ jd += 32045; century = (4 * jd - 1)/ 146097L; jd -= 146097L * century / 4; y = (4 * jd - 1) / 1461; jd -= 1461L * y / 4; y += 100 * century; m = (5 * jd - 3) / 153 + 3; jd -= (153 * m - 457) / 5; if (m > 12) { m -= 12; y++; } *year = y - 4800; *month = m; *day = jd; }