Floor = Math.floor;
function dayfrom20000102(year,month,date) {
year += Floor((month - 3) / 12) - 2000;
month -= Floor((month - 3) / 12) * 12;
return 365 * year - 34 + 30 * month + date + Floor(3 * (month + 1) / 5) + Floor(year / 4) - Floor(year / 100) + Floor(year / 400);
}
function calendardate20100214(gmtdayfrom20000102) {
var calendar = new Object();
calendar.month = Floor(gmtdayfrom20000102 * 12 / 365.2425);
calendar.year = Floor(calendar.month / 12);
calendar.month += 1 - calendar.year * 12;
calendar.year += 2000;
calendar.date = Floor(gmtdayfrom20000102 - dayfrom20000102(calendar.year,calendar.month,0));
while (calendar.date < 1) {
calendar.date += dayfrom20000102(calendar.year,calendar.month,1) - dayfrom20000102(calendar.year,calendar.month - 1,1);
calendar.month--;
calendar.year += Floor((calendar.month - 1) / 12);
calendar.month -= Floor((calendar.month - 1) / 12) * 12;
}
while (gmtdayfrom20000102 >= dayfrom20000102(calendar.year,calendar.month + 1,1)) {
calendar.date -= dayfrom20000102(calendar.year,calendar.month + 1,1) - dayfrom20000102(calendar.year,calendar.month,1);
calendar.month++;
calendar.year += Floor((calendar.month - 1) / 12);
calendar.month -= Floor((calendar.month - 1) / 12) * 12;
}
return calendar;
}
このソースコードはダイヤモンド富士とパール富士の計算で実際に使っている日付計算の関数です。ソースコードをウェブで公開する時長いプログラムが表示範囲より横にはみ出て全部見えないサイトを散見しますが、必ず以下のスタイルを適用したpreタグで表示するようにしてください。
overflow:auto;
横スクロールしても全部見ることができないソースコードは非常に見づらいです。20100214はバレンタインデーだからこの日にしたわけではありません。国立天文台の暦要項にある通りこの日は新月です。旧暦の最初の新月、つまり横浜中華街の春節だった日です。暦屋さんにとってもうれしい日付なのでこの日にしました。2000年1月2日は現代の暦計算の元紀である2000年1月1日12時に最も近い日曜日で、この日を起点として経過日数を計算すると曜日の計算も同時にできて便利だからです。最初に日数計算のライブラリをつくったとき既に2000年のカレンダーは持っていなかったのでこの日が日曜日である事を確認するのにかなり苦労しました。
これはグレゴリオ暦の日数計算の式ですが、グレゴリオ暦だと400年後の同月同日が同じ曜日になるという面白い性質があります。まさに創造主の神秘ですね。ユリウス暦として計算する場合は起点が1999年12月20日で日数計算のdayfrom20000102(year,month,date)の最後の戻り値の行を以下のように変えます。
return 365 * year - 21 + 30 * month + date + Floor(3 * (month + 1) / 5) + Floor(year / 4);
今は年数と経過日数の整数値がlong(JAVAの64bit倍精度整数型)、月、日、時、分、曜日がbyte(JAVAの8bit整数型)、それ以外をBigDecimalという面白い日付オブジェクトをつくっています。経過日数をBigDecimalでもBigIntegerでもなく普通のlong型にしたのはlong型でもビッグバンから現代までの日数より桁が多いからで、システム日付のlong型のミリ秒タイムスタンプの有効範囲を吸収するためです。現象時刻からの経過日数はもちろんBigDecimalです。byteという極めて短い整数型を使うのもその部分がせいぜい2桁の値しか保持しないからです。大は小を兼ねるのでBigDecimalで計算できるようにつくっておくと便利な場面もありますが、割り算は必ず精度の指定が必要だったり計算順序を意識しながら書かないといけないのでけっこうかったるいです。過去の作品にけっこうレガシーメソッドがあったりして自笑しています。
最近のコメント