その最後の方に, グレゴリオ暦の年月日からその日のユリウス日(Julian Day Number)を 計算する式があり, その計算の仕方が面白かったので, 説明したい.
Pythonで書いたその式はこうだ. //は切り捨て除算である.
def jdn(y, m, d):
k = (14 - m) // 12
return (
(- k + y + 4800) * 1461 // 4
+ (k * 12 + m -2) * 367 // 12
- ((- k + y + 4900) // 100) * 3 // 4
+ d - 32075)
私は普段, Schemeを使うので, Schemeで書くとこうだ.
(define (jdn y m d)
(let ((k (quotient (- 14 m) 12)))
(+ (quotient (* (+ (- k) y 4800) 1461) 4)
(quotient (* (+ (* k 12) m -2) 367) 12)
(- (quotient (* (quotient (+ (- k) y 4900) 100) 3) 4))
d -32075)))
暦の計算でなんとも鬱陶しいのは2月の末にあったりなかったりする閏日だ. 今回話題にする
プログラムでは, 1年は3月から始まり, 1月と2月は前年の13月と14月にする扱いである.また紀元前(BC, BCE)はマイナス何年の表記と1年ずれるのも面倒で, 暦の計算ではBCなど は使わないのが普通である.
さて, 「ある日」dのユリウス日jdn(d)の計算には, どこか基準になる日d0とjdnの分かって いる日d1を決め, d0からd1までの通日n(d1)と jdn(d1)の差(Δd)を, dの通日n(d)に足す.
Δd=jdn(d1)-n(d1), jdn(d)=n(d)+Δd
このプログラムでは, d0をユリウス日の開始日の-4712年より前で, 400で整除出来る年の -4800年3月1日として, その日からの通日を使う.
通日の計算は次の図を見て欲しい. いまjdnの分かっている日d1を, グレゴリオ暦への改暦 (1572年)後の1600年3月1日にし, 「ある日」dを1600年10月21日にして, ユリウス日の計算の進行を見よう. この日は 日本の歴史では, 旧暦の慶長5年9月15日, 関ヶ原の合戦があった.
私の「個人用電卓」 で10月21日のjdnを予め計算すると2305742である.
まず-4800年3月1日から1599年14月28日までの, 閏日を無視した長方形を 描く. 閏日は, 4行ごとの最後に入る. 100年毎や400年毎の補正は, 100行ごとの最後, 400行ごとの最後に入る. 長方形の最下行の右端に 飛び出しているのが, 1600年2月(1599年14月)29日で, 1600年は100 で整除出来るが, 400年でも整除出来るから, 閏日は入れる.
365*6400=2336000
4年毎の閏日は 6400/4=1600,
100年毎の閏日は 6400/100=64,
400年毎の閏日は 6400/400=16.
従ってこの(多少の飛出しのある)長方形は, 233600+1600-64+16=2337552. 左下の赤字の値で, 3月1日の 通日である.
次は1600年内の計算で, 3月0日から「ある日」までの通日を計算する. それには3月0日から m月0日までの通日が必要になる. これに,
f(n)=367*n//12
が使えるかもしれない. nを0,1,2,...と替えながらこの値と, f(n+1)とf(n)との差Δfを 計算してみると, 次のようになる.
Δfは赤線のように30と31の12個の列が循環し, 途中31が連続する箇所が2回ある. これが7月, 8月および, 12月, 13月に相当するわけで, mの行に対応する月を記入した. f(n)が各月までの通日になる. 3月までの通日を 0にしたいところだが, それは最後の補正の時にやることにして, これを使う.
大体の様子が分ったので, もう一度プログラムを見る.
def jdn(y, m, d):
k = (14 - m) // 12
return (
(- k + y + 4800) * 1461 // 4
+ (k * 12 + m -2) * 367 // 12
- ((- k + y + 4900) // 100) * 3 // 4
+ d - 32075)
最初のkの値は, mの1から12に対して, 1,1,0,0,0,0,0,0,0,0,0,0,0,0 となり,
1月, 2月を別扱いにする時に使う.次の行, (- k + y + 4800) * 1461 // 4 は, y - k で, 1,2月を前年に繰上げ, -4800を足して基準を-4800年にし, 1461(=365+365+365+366)を掛けて4で 切り捨て除算し, 4年毎の閏日を処理する.
次の行, + (k * 12 + m -2) * 367 // 12 は. m=3, 4, ..., 12を. 1, 2, ..., 14に変換して, m月0日までの通日を得る. 但し3月の欄で見るように30日多い. これは Δに組み込むことにする.
その次の行は100年の補正である. 年を100で割り世紀ごとの補正にする. 0,1,2,3,...,7 について, * 3 // 4をやると, 0, 0, 1, 2, 3, 3, 4, 5,...が得られる. 1,2,3と 増えるのは, 100で割った値が4で割れないで, 閏にしない年, 2行上では4で割れる年はいつも閏にしていたのから これを引いて補正した. 0,0や3,3のように繰り返すのは閏にする年で, 補正にはならない. ただこれを見ると, 補正しないのは-4800年の次の世紀年で, これでは1世紀遅すぎる. その修正のため, ここでは4800ではなく, 4900を足すのである.
改で左下を見ると赤字は前年までの通日, オレンジ色は3月1日までの通日, 従ってn(d1)は 2337583になる. 一方3月1日のユリウス日jdn(d1)は2305508でΔは プログラムにあるように, 32075になる.
1600年10月21のjdnは 2337552+244+21-32075=2305742 と得られた.















