エクセルでマクロを使わず出来るだけ正確に月齢計算と旧暦を求めてみました。
旧暦の毎月の1日は月齢が0(ゼロ)の日になるので、旧暦を求める為には正確な月齢が必要になってきます。
はじめに
月齢や旧暦を計算する言葉やルール
月齢とは、月の満ち欠けの状態を知るための目安の数字です。
月齢が0(ゼロ)の時を新月や朔(さく)と言います。
※新月や朔(さく)の時の月齢が0(ゼロ)と言ったほうがいいのかもしれません。
新月と朔(さく)は同じ意味の言葉です。
新月の方が馴染みがありますね。
月齢や旧暦を求める時は朔(さく)という言葉をよく使います。
朔(さく)は地球から見て月と太陽が同じ方向になった時です。
正確に言うと月と太陽の方向が1mmずれても朔ではなくなります。
朔の瞬間を含む日を朔日と言いますがここでは朔のみと言っています。
旧暦の日
旧暦の日=求める日–求める日の直前の朔+1
例えば、2016年2月3日の旧暦の日を求める場合
2016年2月3日-直前の朔(2016年1月10日)+1=25
2016年2月3日の旧暦の日は25日になります。
旧暦の月
旧暦の月は、二十四節気の二分二至
春分=2月、夏至=5月、秋分=8月、冬至=11月と決まっています。
二分とは春分、秋分で「分」がついている二つのこと
二至とは夏至、冬至で「至」がついている二つのことです。
二十四節気には、節気(せっき)と中気(ちゅうき)があり
朔と朔の間に中気がないと閏月になります。
1985年、2033年、2034年のように例外もあります。
旧暦の年
旧暦の年は、とくに決まりはないですがここでは、新暦の月が3より小さくて旧暦の月が10月より大きい時に新暦の年からマイナス1をしています。
例えば、2016年2月3日の旧暦の年は、新暦の月が2で旧暦の月が12なので旧暦の年は2016-1=2015で2015年になります。
旧暦の日求め方
旧暦の日を求めるには直前の朔を求める必要があります。
直前の朔を求め方
その前に、求める日の直前の二分二至を求めます。
求める日の直前の二分二至
二分二至一覧を作成します。
二分二至一覧は、二十四節気計算で3年分作成して「VLOOKUP関数」で二分二至のみを持ってきています。
二十四節気計算表は【二十四節気計算表作成】で詳しく説明しています。
表4を作成します。
青色のセルG9に求める日の前で一番近い日を二分二至一覧(表2)から持ってきます。
数式「=INDEX(R8:R19,MATCH($A$4,R8:R19))」
ピンク色のところは、中気一覧(下記表3)を二分二至一覧と同じように作成し表4の一番上の二分に至の日付より後で一番近い日、2番目に近い日、3番目に近い日、4番目に近い日を持ってきました。
数式
セルG9「=INDEX($N$8:$N$26,MATCH($G$9,$N$8:$N$26)+1)」
セルG10「=INDEX($N$8:$N$26,MATCH($G$9,$N$8:$N$26)+2)」
セルG11「=INDEX($N$8:$N$26,MATCH($G$9,$N$8:$N$26)+3)」
セルG12「=INDEX($N$8:$N$26,MATCH($G$9,$N$8:$N$26)+4)」
旧暦の月を求める時に使います。
表3
求める日の直前の二分二至の日が分かりました。
次に二分二至の直前の朔を求めます。
二分二至の直前の朔
朔を求めるには月齢を求める必要があります。
月齢計算は【エクセルで月齢計算】で説明します。
月齢が分かっても朔を求めるのに一番苦労しました。
旧暦の1か月は29日か30日でしかも朔の時間は分かっていません。
そこで直前の二分二至の日の月齢を計算し小数点を四捨五入し、その数字を直前の二分二至の日から引きます。
次にその日の翌日と翌々日の23時59分59秒の月齢を求めます。
表1
表1の朔1の3日間です。
セルA14の2015/12/10が直前の二分二至(セルA12 2015/12/22)から11比マイナスした日付です。
セルA15の2015/12/11がその翌日で、セルA16の2015/12/12が翌々日です。
この3日間で月齢の一番数字の小さい日が朔になります。
朔2は朔1から29日後と30日後の日付の23時59分59秒時の月齢を求めます。
そのどちらか0に近い方が朔になります。
朔3、朔4、朔5も同じやり方です。
それぞれの朔を持ってきたのが下記表5の緑色の部分です。
表5
朔1(セルF17)数式「=IF(0=””,””,INDEX(A14:A16,MATCH(MIN(INDEX(ABS((0-B14:B16)),)),INDEX(ABS((0-B14:B16)),),0)))」
朔2(セルF19)数式「=IF($B$18>$B$19,$A$19,$A$18)」
直前の朔
旧暦を求める日の直前の朔は、この表5の緑色の中で求める日の前で一番近い日になります。
例えば、求める日を2016年2月3日にしているので、直前の朔は表5の朔2の2016年1月10日になります。
2016年2月3日-2016年1月10+1=25
2016年2月3日の旧暦の日は25日になります。
旧暦の月の求め方
旧暦の月は、朔と朔の間に中気の何が来るかによって決まってきます。
表5は朔1~朔5を持ってきて、その間に中気を持ってきます。
表5の列Ⅰには二分二至が来た時にの月を表示しています。
列Fの朔の上にはその間の月を表示しています。
黄色の閏(セルE10)は朔と朔の間に閏があれば閏を表示するようにしています。
数式「=IF(A4<F19,E18,IF(A4<F21,E20,IF(A4<F23,E22,IF(A4<F25,E24,E26))))」
黄色の月の下(セルF11)は旧暦を求める日がどの朔と朔の間にあるかで、それに当てはまる月を持ってきます。
数式「=IF(A4<F19,F18,IF(A4<F21,F20,IF(A4<F23,F22,IF(A4<F25,F24,F26))))」
例えば2016年2月3日の旧暦の月を求める場合は、朔2と朔3の間になるので月は12になります。
黄色の月(セルF10)でセルF11の数字が13以上ならマイナス12というようにしています。
数式「=IF(F11>12,F11-12,F11)」
表5を詳しく説明します。
朔1の次(セルG18)は、直前の二分二至がきます。
表4の青色(セルG9)とリンク(式「=G9」)しています。
次の行(セルG19)は表4に朔2と同じ日があれば表示するようにしています。
数式「=IF(ISERROR(VLOOKUP(F19,$G$9:$G$13,1,FALSE)),””,VLOOKUP(F19,$G$9:$G$13,1,FALSE))」
朔の横のセルは同じような数式にしています。
次の行(セルG20」は朔2と朔3の間の日を表示するようにしています。
もし前後の朔と同じ日なら表示されません。
数式「=IF(OR(G19<>””,INDEX($G$9:$G$13,MATCH(F19,$G$9:$G$13)+1)=G21,INDEX($G$9:$G$13,MATCH(F19,$G$9:$G$13)+1)=G22),””,INDEX($G$9:$G$13,MATCH(F19,$G$9:$G$13)+1))」
朔以外の横のセルは同じような数式にしています。
朔1の上(セルF16)からその時の月を表示しています。
セルF16の数式「=IF(I16=””,I18-1,I16)」
※「I16=””」は2033年問題に対応した式です。数式の意味はセルI16に何もなければ二分二至の月(セルI18)からマイナス1した数字を持ってきて、セルI16に何か表示されればそのセルの値をもってくるという数式です。
2033年対策(セルI16)の数式「=IF(AND(A4>=48845,A4<=48933),I18,””)」
※48845と48933はシリアル値で日付に直すと2033月9月23日と2033年12月20日です。数式の意味は2033年9月23日から2033年12月20日まで二分二至の月の数字を持ってくるという数式です。
セルF18の数式「=IF(E18=”閏”,F16,F16+1)」
※セルE8に閏の文字が無ければ前月の月数にプラス1で閏の文字があれば前月と同じ月になるという式です。
セルF20の数式「=IF(E20=”閏”,F18,F18+1)」
セルF22の数式「=IF(E22=”閏”,F20,F20+1)」
セルF24の数式「=IF(E24=”閏”,F22,F22+1)」
セルF26の数式「=F24+1」
朔2、3、4の下(セルE18、E20、E22、E24)には中気が無い時に「閏」の文字が入るようにしています。
セルE18は半角か全角スペース(何も入れないと0(ゼロ)と表示される)
セルE20の数式「=IF(AND(G19=””,G20=””),”閏”,””)」
セルE22の数式「=IF(AND(YEAR(A4)<>1985,G22=””,G21=””),”閏”,””)」
セルE24の数式「=IF(AND(YEAR(A4)<>2034,YEAR(A4)<>2033,G23=””,G24=””),”閏”,””)」
セルE26は半角か全角スペース
※セルE22の「YEAR(A4)<>1985」とセルE24の「YEAR(A4)<>2034,YEAR(A4)<>2033」は1985年、2033年、2034年の閏月がルールに当てはめると変なことになるので変則的になっているのでそれに対応しています。
旧暦の年の求め方
旧暦の年は初めに書いたように求める日の月が3より小さく旧暦の月が10より大きい時は求める日の年からマイナス1します。
図ではセルA6の数式「=IF(AND(MONTH(A4)<3,C6>10),YEAR(A4)-1,YEAR(A4))」
完成品はこちらでダウンロードできます。【月齢旧暦計算】(zip)クリックするとダウンロードします。
小生,20年ほど前に月齢計算→旧暦計算を管理工学社の「桐」で挑戦しましたが,暦の計算において基本となる場所が京都御所であることわかり,計算が非常に複雑となり,及び,表計算ソフトのような表参照を得意としていないデータベースソフト欠点から,当時の「桐」のプログラム枠を超えたので,旧暦計算を諦めたことがありました。
このたび,syundoさんの記事を読み,久しぶりに触発されました。これからしばらくプログラ解析を楽しましていただきます。