カレンダー計算(1)日付からMJDへの変換
概要
天文計算や暦計算で使われる、日付と修正ユリウス日の間の変換方法。
以下のような計算に役立つ。
- 曜日の計算
- ユリウス暦とグレゴリオ暦の間の変換
- 2つの日付間の日数の計算
今回は日付から修正ユリウス日への変換方法。
日付を日数で表す
年月日で表される日付は、年・月・日の軸をもつ3次元空間に並べられた点の集まりと解釈できる。
しかし天文や暦の計算においては、日付は1次元の線上に並べたほうが扱い易くなる。
すなわち、ある特定の日を第0日とし、そこから通算の経過日数で日付を表すという方法である。
ユリウス日、ユリウス通日(Julian Day、JD)
- 紀元前4713年1月1日正午(ユリウス暦)を第0日としたときの通算の日数で日付を表したもの。
- 正負の整数であれば正午を表すが、小数部で時刻を表す。
2025年1月1日の正午で、2,460,677になる。
修正ユリウス日、準ユリウス日(Modified Julian Day、MJD)
- ユリウス日よりも小さい桁で日付を扱えるよう考え出された。
- ユリウス日から2400000.5日を引いたものとして定義される。
- 1858年11月17日(グレゴリオ暦)を第0日としたときの通算の日数で日付を表す。
- 正負の整数であれば午前0時を表すが、小数部で時刻を表す。
2025年1月1日の午前0時で60,676になる。
西暦
西暦には、うるう年をどのように定めるかによって、ユリウス暦とグレゴリオ暦がある。現在使われているのはグレゴリオ暦。
ユリウス暦
以下のルールがある。
- うるう年は4年に1回。
すなわち、4年は1,461日(=365×3+366)、1年は365.25日(=1,461/4)。実際の1太陽年(地球の公転周期/自転周期)はおよそ365.2422(日)なので、ユリウス暦では1年あたり365.2422-365.25=-0.0078日の誤差が生じる。1600年経てば約12.5日ずれる。
ユリウス暦は紀元前45年にローマで導入された。
当初は4年に1回とすべきうるう年を、3年に1回で誤運用していた。誤りに気づいた後、調整の為うるう年を設けない期間が設けられ、西暦8年のうるう年以降は4年に1回で運用された。
このへんの歴史は考慮せず、後に出てくるプログラムでは、ユリウス暦は単純に4年に1回のうるう年を設けている。
グレゴリオ暦
以下のルールがある。
- うるう年は4年に1回
- ただし100年に1回(西暦が100で割り切れる年)はうるう年を取消し。
- ただし400年に1回(西暦が400で割り切れる年)はうるう年。
すなわち400年のうちうるう年は400/4-4+1=97回あるので、400年は146,097日(=365×303+366×97)、1年は365.2425日(=146,097/400)。グレゴリオ暦では1年あたり365.2422-365.2425=-0.0003日の誤差が生じる。1600年経てば約0.5日ずれる。1万年経っても約3日しかずれない。
グレゴリオ暦は、ユリウス暦1582年10月4日の翌日、グレゴリオ暦1582年10月15日からローマで採用された。
グレゴリオ暦の導入時期は国によって異なり、日本では旧暦明治5年12月2日の翌日、新暦明治6年1月1日から開始された。
紀元前の表現
西暦1年の前年は紀元前1年だが、天文学では年数計算を簡便にする為、紀元前1年を西暦0年、紀元前2年を西暦-1年、・・、紀元前N年を西暦-(N-1)年とする紀年法が使われる。
以下のプログラムもこれに従う。たとえば紀元前4713年は-4712年と表示する。
曜日と日干支の算出方法
曜日
(修正ユリウス日+3)を7で割った余りから曜日が得られる
(0:日、1:月、2:火、3:水、4:木、5:金、6:土)
日干支
- 修正ユリウス日を10で割った余りから十干が得られる
(0:甲、1:乙、2:丙、3:丁、4:戊、5:己、6:庚、7:辛、8:壬、9:癸) - (修正ユリウス日+2)を12で割った余りから十二支が得られる
(0:子、1丑、2:寅、3:卯、4:辰、5:巳、6:午、7:未、8:申、9:酉、10:戌、11:亥)
ユリウス日、修正ユリウス日を計算する
年月日から修正ユリウス日を算出して表示するプログラム。
曜日と日干支も表示する。
'修正ユリウス日(MJD)を計算する
Dim dt
Dim buf
Dim Y, M ,D
Dim mjd1 'グレゴリオ暦の日付から算出したMJD
Dim mjd2 'ユリウス暦の日付から算出したMJD
Dim msg '表示するメッセージ
dt = Date() '本日をデフォルト値とする
Do
dt = InputBox("日付を入力して下さい", , dt)
If dt = "" Then Exit Do 'キャンセルが押されたら終了
buf = Split(dt, "/") '年,月,日の配列
Y = CDbl(buf(0)) '年, 数値へ変換
M = CDbl(buf(1)) '月, 数値へ変換
D = CDbl(buf(2)) '日, 数値へ変換
'1,2月を前年の13,14月にする
If M < 3 Then
Y = Y - 1
M = M + 12
End If
'グレゴリオ暦の日付から修正ユリウス日を算出
mjd1 = - 678882 + 365 * Y + MonthDay(M - 1) + D + Int(Y / 4) _
- Int(Y / 100) + Int(Y / 400)
'ユリウス暦の日付から修正ユリウス日を算出
mjd2 = - 678884 + 365 * Y + MonthDay(M - 1) + D + Int(Y / 4)
'表示するメッセージ
msg = "グレゴリオ暦の" & dt & "は" & vbCr _
& "MJD=" & mjd1 & "、" & GetWeek(mjd1) _
& "、" & GetEto(mjd1) & vbCr & vbCr _
& "ユリウス暦の" & dt & "は" & vbCr _
& "MJD=" & mjd2 & "、" & GetWeek(mjd2) _
& "、" & GetEto(mjd2)
Msgbox msg,, "修正ユリウス日"
Loop
Function MonthDay(M)
'2月末日を第0日としてM月末日までの日数を返す(M=2~13)
MonthDay = Int(30.59 * (M - 1)) - 30
End Function
Function GetWeek(mjd)
Dim p
p = (mjd + 3) Mod 7
If p < 0 Then p = p + 7
GetWeek = Mid("日月火水木金土", p+1, 1) & "曜日"
End Function
Function GetEto(mjd)
Dim p1, p2
p1 = mjd Mod 10
If p1 < 0 Then p1 = p1 + 10
p2 = (mjd + 2) Mod 12
If p2 < 0 Then p2 = p2 + 12
GetEto = Mid("甲乙丙丁戊己庚辛壬癸", p1+1, 1) _
& Mid("子丑寅卯辰巳午未申酉戌亥", p2+1, 1)
End Function
Function MonthDay(M)
'2月末日を第0日としてM月末日までの日数を返す(M=2~13)
MonthDay = Int(30.59 * (M - 1)) - 30
End Function
- 1,2月を13,14月に変換するのは、計算上2月末日を1年の最終日、もしくは翌年の第0日として扱うため。
- 計算式に出てくる-678882と-678884は、それぞれグレゴリオ暦とユリウス暦における紀元前1年2月29日のMJD。
実行例
ダブルクリックして日付を入力すると、ダイアログボックスが表示される。以下は2025/1/1
と入力した場合の表示例。
グレゴリオ暦の2025/1/1は
MJD=60676、水曜日、庚午
ユリウス暦の2025/1/1は
MJD=60689、火曜日、癸未
参考
- ユリウス通日(Wikipedia)
- マイコン宇宙講座―楽しい軌道計算プログラム(中野圭一著)