實歷冬至合朔表(BC722-BC104)

利用python的pyephem模塊(需先安裝)可以很容易獲得合朔及冬至時間。但需注意,該模塊在曆元2000.0年±3000年的平均誤差在10分鐘以內,但此外的誤差是難以接受的。

關於朔旦冬至的判斷:冬至月判斷可能存在的幾個誤差。

  1. 現代測算誤差:現代的天文計算,是近代天文學發展起來以後利用精密儀器測量天體的實際運行狀況,由此構建的理論模型。但天體的運動狀況非常複雜,當今的測量結果能難適用於久遠前或久遠後的宇宙,距離時間越遠,誤差越大。對於先秦時期的歷表,應注意定朔或冬至時間在0-1時或23-24時段,可能幾分鐘的誤差在進位時表現爲1天。
  2. 古代測算誤差:戰國前後是以冬至所在的月份作爲正月,但月朔是無法觀測的,推朔會有誤差,而冬至的測量也存在誤差。以《左傳》兩次“日南至”的記載爲例,皆與今測算差2日。

歷表的排布:每個冬至合朔點有3項數據(干支、日期、時間),其中時間部分主要用於參考可能的誤差問題,分三行排列。每年從冬至月起排,如果到下一個冬至月出現了13次合朔,該年則排出13個月份,但並不表示該年存在閏月,月名僅供參考。古代的置閏會因爲不同的歷元和置閏方法有變化。如果連續兩個月朔日干支的天干部分相同,說明前一個月爲大月,否則爲小月。如果連續三個月朔日干支的天干部分相同,說明前兩個月爲連大月。古歷的朔策較今值爲大,大小月的情況也與實歷不符。

wangnian部分的代碼參見:https://blog.csdn.net/weixin_42763614/article/details/82955539

import ephem
from wangnian import *

nlrq = ["初一","初二","初三","初四","初五","初六","初七","初八","初九","初十","十一","十二","十三","十四","十五","十六","十七","十八","十九","二十","二一","二二","二三","二四","二五","二六","二七","二八","二九","三十"]

def jd2ce(JD):
	JD = JD + 0.5  # 以-4812年1月1日0時爲曆元
	Z = int(JD)
	F = JD - Z
	if Z < 2299161:  # 儒略曆
		A = Z
	else:  # 格里曆
		a = int((Z - 1867216.25) / 36524.25)
		A = Z + 1 + a - int(a / 4)
	B = A + 1524
	C = int((B - 122.1) / 365.25)
	D = int(365.25 * C)
	E = int((B - D) / 30.6001)
	day = B - D - int(30.6001 * E) + F
	if E < 14:
		month = E - 1
	elif E < 16:
		month = E - 13
	if month > 2:
		year = C - 4716
	elif month in [1, 2]:
		year = C - 4715
	d = day - int(day) #取出一日的小數部分,轉換爲時分秒
	h = int(d * 24)
	m = int((d * 24 - h) * 60)
	s = ((d *24 - h) * 60 - int((d *24 - h) * 60)) * 60
	if year <= 0: # 將天文年表示爲公曆年
		year -= 1
	return year, month, int(day),h,m,round(s)

def ut8(t): # 由UT0h轉爲UT8h
	d = ephem.Date(t)
	date = d.tuple() # 獲得年月日時分秒
	jd0 = ephem.julian_date(t)
	jd = jd0 + 8/24
	ce = jd2ce(jd)
	return ce

def jd2gz(t):
	JD = ephem.julian_date(t)
	tiangan = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
	dizhi = ["子", "醜", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
	gz = [''] * 60  # 六十甲子表
	for i in range(60):		gz[i] = tiangan[i % 10] + dizhi[i % 12]
	return gz[int(JD+0.5+8/24+49)%60]

def time_format(t,type):
	if type == 0: # 日期
		return "BC{}-{:02d}-{:02d}".format(-ut8(t)[0],ut8(t)[1],ut8(t)[2])
	elif type == 1: # 時間
		return "{:02d}:{:02d}:{:02d}".format(ut8(t)[3], ut8(t)[4], ut8(t)[5])

header = ["參考年","王公紀年","冬至",'冬至日期',"冬至月朔","二月(醜)","三月(寅)","四月","五月","六月","七月","八月","九月","十月","十一月","十二月","十三月"]
dzhsb = open("冬至合朔表.xls",'w')
for i in range(len(header)):
	dzhsb.write(header[i]+'\t')

for i in range(620): # BC722-BC104
	year = -723 + i
	time = str(year)+'/12'
	dz = ephem.next_solstice(time) # 冬至時間
	dz_jd = ephem.julian_date(dz)  # 冬至儒略日
	dzs0 = jd2ce(dz_jd - 29) # 冬至前一月
	dzs = ephem.next_new_moon(dzs0) # 預判的冬至朔
	dzs_jd = ephem.julian_date(dzs) # 在UT8h下比較冬至朔是否爲實際的冬至所在月朔日
	if int(dz_jd+0.5+8/24) < int(dzs_jd+0.5+8/24):
		dzs = ephem.next_new_moon(jd2ce(dz_jd - 30))
		dzs_jd = ephem.julian_date(dzs)
	# 寫入上一年曆表
	if i != 0:
		if str(heshuo) == str(dzs):
			hsb.pop() # 上年最後一月朔爲是年冬至朔,則刪除
		dzhsb.write('\n')
		for m in range(3):
			dzhsb.write(hsb[0][0]+'\t')  # 參考年
			dzhsb.write(hsb[0][1]+'\t')  # 王公紀年年
			for n in range(len(hsb)): # 月表
				if n == 0 : continue
				if n == 2 : # 在冬至後插入冬至的日期
					if m == 1: dzhsb.write(dzrq)
					dzhsb.write('\t')
				dzhsb.write(hsb[n][m+0]+'\t')
			dzhsb.write('\n')
		hsb.clear()
	# 生成歷表
	hsb = [[str(year + 1), wgjn[841 + year + 1]]]
	hsb.extend([[jd2gz(dz),time_format(dz,0),time_format(dz,1)]]) # 干支,年月日,時分秒
	hsb.extend([[jd2gz(dzs),time_format(dzs,0),time_format(dzs,1)]])
	dzrq = nlrq[int(dz_jd+0.5+8/24)-int(dzs_jd+0.5+8/24)]
	for j in range(12): # 冬至以後的每月合朔表
		hs = jd2ce(dzs_jd + 29*(j+1)) # 估測的合朔日期
		heshuo = ephem.next_new_moon(hs) # 實際合朔日期
		hsb.extend([[jd2gz(heshuo),time_format(heshuo,0),time_format(heshuo,1)]])

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章