From 460e042aa951d79b0ead75e79020955074d7b5c0 Mon Sep 17 00:00:00 2001 From: Starainrt Date: Mon, 15 Jan 2024 17:05:18 +0800 Subject: [PATCH] update rapid lunar calc --- basic/calendar.go | 48 +-- basic/calendar_test.go | 126 ++++++ basic/moon.go | 15 +- basic/moon_test.go | 43 ++ basic/sun.go | 827 +++------------------------------------ basic/sun_test.go | 52 ++- calendar/chinese.go | 141 +++++++ calendar/chinese_test.go | 5 +- 8 files changed, 449 insertions(+), 808 deletions(-) create mode 100644 basic/calendar_test.go diff --git a/basic/calendar.go b/basic/calendar.go index 96f3306..c3647e5 100644 --- a/basic/calendar.go +++ b/basic/calendar.go @@ -265,33 +265,33 @@ func GetLunar(year, month, day int, tz float64) (lmonth, lday int, leap bool, re } else { year-- } - jieqi := GetOneYearJQ(year) //一年的节气 - moon := GetOneYearMoon(float64(year)) //一年朔月日 - winter1 := jieqi[1] - 8.0/24 + tz //第一年冬至日 - winter2 := jieqi[25] - 8.0/24 + tz //第二年冬至日 - for k, v := range moon { + jieqi := GetJieqiLoops(year, 25) //一年的节气 + moon := GetMoonLoops(float64(year), 17) //一年朔月日 + winter1 := jieqi[0] - 8.0/24 + tz //第一年冬至日 + winter2 := jieqi[24] - 8.0/24 + tz //第二年冬至日 + for idx, v := range moon { if tz != 8.0/24 { v = v - 8.0/24 + tz } if v-math.Floor(v) > 0.5 { - moon[k] = math.Floor(v) + 0.5 + moon[idx] = math.Floor(v) + 0.5 } else { - moon[k] = math.Floor(v) - 0.5 + moon[idx] = math.Floor(v) - 0.5 } } //置闰月为0点 - for k, v := range jieqi { + for idx, v := range jieqi { if tz != 8.0/24 { v = v - 8.0/24 + tz } if v-math.Floor(v) > 0.5 { - jieqi[k] = math.Floor(v) + 0.5 + jieqi[idx] = math.Floor(v) + 0.5 } else { - jieqi[k] = math.Floor(v) - 0.5 + jieqi[idx] = math.Floor(v) - 0.5 } } //置节气为0点 mooncount := 0 //年内朔望月计数 var min, max int = 20, 0 //最大最小计数 - for i := 1; i < 16; i++ { + for i := 0; i < 15; i++ { if moon[i] >= winter1 && moon[i] < winter2 { if i <= min { min = i @@ -304,7 +304,7 @@ func GetLunar(year, month, day int, tz float64) (lmonth, lday int, leap bool, re } leapmonth := 20 if mooncount == 13 { //存在闰月 - j, i := 3, 1 + var j, i = 2, 0 for i = min; i <= max; i++ { if !(moon[i] <= jieqi[j] && moon[i+1] > jieqi[j]) { break @@ -364,33 +364,33 @@ func GetSolar(year, month, day int, leap bool, tz float64) float64 { if month < 11 { year-- } - jieqi := GetOneYearJQ(year) //一年的节气 - moon := GetOneYearMoon(float64(year)) //一年朔月日 - winter1 := jieqi[1] - 8.0/24 + tz //第一年冬至日 - winter2 := jieqi[25] - 8.0/24 + tz //第二年冬至日 - for k, v := range moon { + jieqi := GetJieqiLoops(year, 25) //一年的节气 + moon := GetMoonLoops(float64(year), 17) //一年朔月日 + winter1 := jieqi[0] - 8.0/24 + tz //第一年冬至日 + winter2 := jieqi[24] - 8.0/24 + tz //第二年冬至日 + for idx, v := range moon { if tz != 8.0/24 { v = v - 8.0/24 + tz } if v-math.Floor(v) > 0.5 { - moon[k] = math.Floor(v) + 0.5 + moon[idx] = math.Floor(v) + 0.5 } else { - moon[k] = math.Floor(v) - 0.5 + moon[idx] = math.Floor(v) - 0.5 } } //置闰月为0点 - for k, v := range jieqi { + for idx, v := range jieqi { if tz != 8.0/24 { v = v - 8.0/24 + tz } if v-math.Floor(v) > 0.5 { - jieqi[k] = math.Floor(v) + 0.5 + jieqi[idx] = math.Floor(v) + 0.5 } else { - jieqi[k] = math.Floor(v) - 0.5 + jieqi[idx] = math.Floor(v) - 0.5 } } //置节气为0点 mooncount := 0 //年内朔望月计数 var min, max int = 20, 0 //最大最小计数 - for i := 1; i < 16; i++ { + for i := 0; i < 15; i++ { if moon[i] >= winter1 && moon[i] < winter2 { if i <= min { min = i @@ -403,7 +403,7 @@ func GetSolar(year, month, day int, leap bool, tz float64) float64 { } leapmonth := 20 if mooncount == 13 { //存在闰月 - j, i := 3, 1 + var j, i = 2, 0 for i = min; i <= max; i++ { if !(moon[i] <= jieqi[j] && moon[i+1] > jieqi[j]) { break diff --git a/basic/calendar_test.go b/basic/calendar_test.go new file mode 100644 index 0000000..30bb633 --- /dev/null +++ b/basic/calendar_test.go @@ -0,0 +1,126 @@ +package basic + +import ( + "encoding/json" + "fmt" + "math" + "os" +) + +func generateMagicNumber() { + //0月份 00000 日期 0000闰月 0000000000000 农历信息 + var tz = 8.0000 / 24.000 + yearMap := make(map[int][][]int) // {1 month,1 leap,2 29/30} + spYear := make(map[int][]int) + var upper []uint16 + var lower []uint16 + //var info uint32 = 0 + for year := 1899; year <= 2401; year++ { + fmt.Println(year) + jieqi := GetJieqiLoops(year, 25) //一年的节气 + moon := GetMoonLoops(float64(year), 17) //一年朔月日 + winter1 := jieqi[0] - 8.0/24 + tz //第一年冬至日 + winter2 := jieqi[24] - 8.0/24 + tz //第二年冬至日 + for idx, v := range moon { + if tz != 8.0/24 { + v = v - 8.0/24 + tz + } + if v-math.Floor(v) > 0.5 { + moon[idx] = math.Floor(v) + 0.5 + } else { + moon[idx] = math.Floor(v) - 0.5 + } + } //置闰月为0点 + for idx, v := range jieqi { + if tz != 8.0/24 { + v = v - 8.0/24 + tz + } + if v-math.Floor(v) > 0.5 { + jieqi[idx] = math.Floor(v) + 0.5 + } else { + jieqi[idx] = math.Floor(v) - 0.5 + } + } //置节气为0点 + mooncount := 0 //年内朔望月计数 + var min, max int = 20, 0 //最大最小计数 + for i := 0; i < 15; i++ { + if moon[i] >= winter1 && moon[i] < winter2 { + if i <= min { + min = i + } + if i >= max { + max = i + } + mooncount++ + } + } + leapmonth := 20 + if mooncount == 13 { //存在闰月 + var j, i = 2, 0 + for i = min; i <= max; i++ { + if !(moon[i] <= jieqi[j] && moon[i+1] > jieqi[j]) { + break + } + j += 2 + } + leapmonth = i - min + 1 + } + month := 11 + for idx := min; idx <= max; idx++ { + leap := 0 + if idx != leapmonth { + month++ + if month > 12 { + month -= 12 + } + } else { + leap = 1 + } + if leap == 0 && month == 1 { + cp := JDE2Date(moon[idx]) + spYear[year+1] = append(spYear[year+1], []int{int(cp.Month()), cp.Day()}...) + } + if idx < 6 && month > 10 { + yearMap[year] = append(yearMap[year], []int{month, leap, int(moon[idx+1] - moon[idx])}) + } else { + yearMap[year+1] = append(yearMap[year+1], []int{month, leap, int(moon[idx+1] - moon[idx])}) + } + } + } + for year := 1900; year <= 2400; year++ { + fmt.Println(year) + up, low := magicNumberSpilt(magicNumber(yearMap[year], spYear[year])) + upper = append(upper, up) + lower = append(lower, uint16(low)) + } + res := make(map[string]interface{}) + res["up"] = upper + res["low"] = lower + d, _ := json.Marshal(res) + os.WriteFile("test.json", d, 0644) +} + +func magicNumber(y1 [][]int, y2 []int) int32 { + var res int32 + res = int32(y2[1]) << 18 + if y2[0] == 2 { + res = res | 0x800000 + } + for idx, v := range y1 { + if v[2] == 30 { + res = res | (1 << (13 - idx)) + } + if v[1] == 1 { + res = (res & 0xFC3FFF) | int32((v[0])<<14) + } + } + return res +} + +func magicNumberSpilt(magic int32) (uint16, uint8) { + var upper uint16 + var lower uint8 + lower = uint8(magic) + upper = uint16(magic >> 8) + return upper, lower +} diff --git a/basic/moon.go b/basic/moon.go index 220be8c..2bc1139 100644 --- a/basic/moon.go +++ b/basic/moon.go @@ -1055,9 +1055,15 @@ func MoonTrueRa(JD float64) float64 { return LoToRa(JD, MoonApparentLo(JD), MoonTrueBo(JD)) } -/** - * - 传入世界时 +func MoonTrueRaDec(JD float64) (float64, float64) { + return LoBoToRaDec(JD, MoonApparentLo(JD), MoonTrueBo(JD)) +} + +/* +* + + * + 传入世界时 */ func MoonApparentRa(JD, lon, lat float64, tz int) float64 { jde := TD2UT(JD, true) @@ -1702,7 +1708,8 @@ func HMoonTrueRa(JD float64) float64 { return LoToRa(JD, HMoonApparentLo(JD), HMoonTrueBo(JD)) } -/** +/* +* * 传入世界时 */ diff --git a/basic/moon_test.go b/basic/moon_test.go index 8c7c050..18753e8 100644 --- a/basic/moon_test.go +++ b/basic/moon_test.go @@ -1,6 +1,7 @@ package basic import ( + "b612.me/astro/tools" "fmt" "math" "testing" @@ -21,7 +22,49 @@ func Test_MoonDown(t *testing.T) { fmt.Println(i, GetMoonDownTime(jde, 115, float64(i), 8, 1, 0)) } } +func Test_MoonDiff(t *testing.T) { + n := JDECalc(2000, 1, 1) + var maxRa, maxDec, maxLo, maxBo float64 + for i := float64(0); i < 365.2422*3; i++ { + tLo := HMoonApparentLo(n + i) + tBo := HMoonTrueBo(n + i) + tRa, tDec := HMoonTrueRaDec(n + i) + fRa, fDec := MoonTrueRaDec(n + i) + fLo := MoonApparentLo(n + i) + fBo := MoonTrueBo(n + i) + tmp := tools.Limit360(math.Abs(tRa - fRa)) + if tmp > 300 { + tmp = 360 - tmp + } + if tmp > maxRa { + maxRa = tmp + } + tmp = tools.Limit360(math.Abs(tDec - fDec)) + if tmp > 300 { + tmp = 360 - tmp + } + if tmp > maxDec { + maxDec = tmp + } + tmp = tools.Limit360(math.Abs(tLo - fLo)) + if tmp > 300 { + tmp = 360 - tmp + } + if tmp > maxLo { + maxLo = tmp + } + + tmp = tools.Limit360(math.Abs(tBo - fBo)) + if tmp > 300 { + tmp = 360 - tmp + } + if tmp > maxBo { + maxBo = tmp + } + } + fmt.Printf("%.15f %.15f %.15f %.15f\n", maxRa*3600, maxDec*3600, maxLo*3600, maxBo*3600) +} func Test_MoonRise(t *testing.T) { //2.459984692085961e+06 113.58880556 87.36833333 8 0 0 //2.459984692085961e+06 113.58880556 87.36833333 8 0 0 diff --git a/basic/sun.go b/basic/sun.go index 13f4ed4..876bc03 100644 --- a/basic/sun.go +++ b/basic/sun.go @@ -8,7 +8,7 @@ import ( ) /* - 黄赤交角、nutation==true时,计算交角章动 +黄赤交角、nutation==true时,计算交角章动 */ func EclipticObliquity(jde float64, nutation bool) float64 { U := (jde - 2451545) / 3652500.000 @@ -27,771 +27,47 @@ func Sita(JD float64) float64 { /* * @name 黄经章动 */ -func HJZD(JD float64) float64 { // '黄经章动 - - // Dim p As Double, T As Double, Lmoon As Double - T := (JD - 2451545) / 36525.000 - D := 297.8502042 + 445267.1115168*T - 0.0016300*T*T + T*T*T/545868 - T*T*T*T/113065000 - M := SunM(JD) - N := MoonM(JD) - F := MoonLonX(JD) - O := 125.04452 - 1934.136261*T + 0.0020708*T*T + T*T*T/450000 - //die(T." ".D." ".M." ".N." ".F." ".O); - tp := make(map[int]map[int]float64) - for i := 1; i < 64; i++ { - tp[i] = make(map[int]float64) - } - tp[1][1] = 0 - tp[1][2] = 0 - tp[1][3] = 0 - tp[1][4] = 0 - tp[1][5] = 1 - tp[1][6] = -171996 - tp[1][7] = -174.2 * T - tp[2][1] = -2 - tp[2][2] = 0 - tp[2][3] = 0 - tp[2][4] = 2 - tp[2][5] = 2 - tp[2][6] = -13187 - tp[2][7] = -1.6 * T - tp[3][1] = 0 - tp[3][2] = 0 - tp[3][3] = 0 - tp[3][4] = 2 - tp[3][5] = 2 - tp[3][6] = -2274 - tp[3][7] = -0.2 * T - tp[4][1] = 0 - tp[4][2] = 0 - tp[4][3] = 0 - tp[4][4] = 0 - tp[4][5] = 2 - tp[4][6] = 2062 - tp[4][7] = 0.2 * T - tp[5][1] = 0 - tp[5][2] = 1 - tp[5][3] = 0 - tp[5][4] = 0 - tp[5][5] = 0 - tp[5][6] = 1426 - tp[5][7] = -3.4 * T - tp[6][1] = 0 - tp[6][2] = 0 - tp[6][3] = 1 - tp[6][4] = 0 - tp[6][5] = 0 - tp[6][6] = 712 - tp[6][7] = 0.1 * T - tp[7][1] = -2 - tp[7][2] = 1 - tp[7][3] = 0 - tp[7][4] = 2 - tp[7][5] = 2 - tp[7][6] = -517 - tp[7][7] = 1.2 * T - tp[8][1] = 0 - tp[8][2] = 0 - tp[8][3] = 0 - tp[8][4] = 2 - tp[8][5] = 1 - tp[8][6] = -386 - tp[8][7] = -0.4 * T - tp[9][1] = 0 - tp[9][2] = 0 - tp[9][3] = 1 - tp[9][4] = 2 - tp[9][5] = 2 - tp[9][6] = -301 - tp[9][7] = 0 - tp[10][1] = -2 - tp[10][2] = -1 - tp[10][3] = 0 - tp[10][4] = 2 - tp[10][5] = 2 - tp[10][6] = 217 - tp[10][7] = -0.5 * T - tp[11][1] = -2 - tp[11][2] = 0 - tp[11][3] = 1 - tp[11][4] = 0 - tp[11][5] = 0 - tp[11][6] = -158 - tp[11][7] = 0 - tp[12][1] = -2 - tp[12][2] = 0 - tp[12][3] = 0 - tp[12][4] = 2 - tp[12][5] = 1 - tp[12][6] = 129 - tp[12][7] = 0.1 * T - tp[13][1] = 0 - tp[13][2] = 0 - tp[13][3] = -1 - tp[13][4] = 2 - tp[13][5] = 2 - tp[13][6] = 123 - tp[13][7] = 0 - tp[14][1] = 2 - tp[14][2] = 0 - tp[14][3] = 0 - tp[14][4] = 0 - tp[14][5] = 0 - tp[14][6] = 63 - tp[14][7] = 0 - tp[15][1] = 0 - tp[15][2] = 0 - tp[15][3] = 1 - tp[15][4] = 0 - tp[15][5] = 1 - tp[15][6] = 63 - tp[15][7] = 0.1 * T - tp[16][1] = 2 - tp[16][2] = 0 - tp[16][3] = -1 - tp[16][4] = 2 - tp[16][5] = 2 - tp[16][6] = -59 - tp[16][7] = 0 - tp[17][1] = 0 - tp[17][2] = 0 - tp[17][3] = -1 - tp[17][4] = 0 - tp[17][5] = 1 - tp[17][6] = -58 - tp[17][7] = -0.1 * T - tp[18][1] = 0 - tp[18][2] = 0 - tp[18][3] = 1 - tp[18][4] = 2 - tp[18][5] = 1 - tp[18][6] = -51 - tp[18][7] = 0 - tp[19][1] = -2 - tp[19][2] = 0 - tp[19][3] = 2 - tp[19][4] = 0 - tp[19][5] = 0 - tp[19][6] = 48 - tp[19][7] = 0 - tp[20][1] = 0 - tp[20][2] = 0 - tp[20][3] = -2 - tp[20][4] = 2 - tp[20][5] = 1 - tp[20][6] = 46 - tp[20][7] = 0 - tp[21][1] = 2 - tp[21][2] = 0 - tp[21][3] = 0 - tp[21][4] = 2 - tp[21][5] = 2 - tp[21][6] = -38 - tp[21][7] = 0 - tp[22][1] = 0 - tp[22][2] = 0 - tp[22][3] = 2 - tp[22][4] = 2 - tp[22][5] = 2 - tp[22][6] = -31 - tp[22][7] = 0 - tp[23][1] = 0 - tp[23][2] = 0 - tp[23][3] = 2 - tp[23][4] = 0 - tp[23][5] = 0 - tp[23][6] = 29 - tp[23][7] = 0 - tp[24][1] = -2 - tp[24][2] = 0 - tp[24][3] = 1 - tp[24][4] = 2 - tp[24][5] = 2 - tp[24][6] = 29 - tp[24][7] = 0 - tp[25][1] = 0 - tp[25][2] = 0 - tp[25][3] = 0 - tp[25][4] = 2 - tp[25][5] = 0 - tp[25][6] = 26 - tp[25][7] = 0 - tp[26][1] = -2 - tp[26][2] = 0 - tp[26][3] = 0 - tp[26][4] = 2 - tp[26][5] = 0 - tp[26][6] = -22 - tp[26][7] = 0 - tp[27][1] = 0 - tp[27][2] = 0 - tp[27][3] = -1 - tp[27][4] = 2 - tp[27][5] = 1 - tp[27][6] = 21 - tp[27][7] = 0 - tp[28][1] = 0 - tp[28][2] = 2 - tp[28][3] = 0 - tp[28][4] = 0 - tp[28][5] = 0 - tp[28][6] = 17 - tp[28][7] = -0.1 * T - tp[29][1] = 2 - tp[29][2] = 0 - tp[29][3] = -1 - tp[29][4] = 0 - tp[29][5] = 1 - tp[29][6] = 16 - tp[29][7] = 0 - tp[30][1] = -2 - tp[30][2] = 2 - tp[30][3] = 0 - tp[30][4] = 2 - tp[30][5] = 2 - tp[30][6] = -16 - tp[30][7] = 0.1 * T - tp[31][1] = 0 - tp[31][2] = 1 - tp[31][3] = 0 - tp[31][4] = 0 - tp[31][5] = 1 - tp[31][6] = -15 - tp[31][7] = 0 - tp[32][1] = -2 - tp[32][2] = 0 - tp[32][3] = 1 - tp[32][4] = 0 - tp[32][5] = 1 - tp[32][6] = -13 - tp[32][7] = 0 - tp[33][1] = 0 - tp[33][2] = -1 - tp[33][3] = 0 - tp[33][4] = 0 - tp[33][5] = 1 - tp[33][6] = -12 - tp[33][7] = 0 - tp[34][1] = 0 - tp[34][2] = 0 - tp[34][3] = 2 - tp[34][4] = -2 - tp[34][5] = 0 - tp[34][6] = 11 - tp[34][7] = 0 - tp[35][1] = 2 - tp[35][2] = 0 - tp[35][3] = -1 - tp[35][4] = 2 - tp[35][5] = 1 - tp[35][6] = -10 - tp[35][7] = 0 - tp[36][1] = 2 - tp[36][2] = 0 - tp[36][3] = 1 - tp[36][4] = 2 - tp[36][5] = 2 - tp[36][6] = -8 - tp[36][7] = 0 - tp[37][1] = 0 - tp[37][2] = 1 - tp[37][3] = 0 - tp[37][4] = 2 - tp[37][5] = 2 - tp[37][6] = 7 - tp[37][7] = 0 - tp[38][1] = -2 - tp[38][2] = 1 - tp[38][3] = 1 - tp[38][4] = 0 - tp[38][5] = 0 - tp[38][6] = -7 - tp[38][7] = 0 - tp[39][1] = 0 - tp[39][2] = -1 - tp[39][3] = 0 - tp[39][4] = 2 - tp[39][5] = 2 - tp[39][6] = -7 - tp[39][7] = 0 - tp[40][1] = 2 - tp[40][2] = 0 - tp[40][3] = 0 - tp[40][4] = 2 - tp[40][5] = 1 - tp[40][6] = -7 - tp[40][7] = 0 - tp[41][1] = 2 - tp[41][2] = 0 - tp[41][3] = 1 - tp[41][4] = 0 - tp[41][5] = 0 - tp[41][6] = 6 - tp[41][7] = 0 - tp[42][1] = -2 - tp[42][2] = 0 - tp[42][3] = 2 - tp[42][4] = 2 - tp[42][5] = 2 - tp[42][6] = 6 - tp[42][7] = 0 - tp[43][1] = -2 - tp[43][2] = 0 - tp[43][3] = 1 - tp[43][4] = 2 - tp[43][5] = 1 - tp[43][6] = 6 - tp[43][7] = 0 - tp[44][1] = 2 - tp[44][2] = 0 - tp[44][3] = -2 - tp[44][4] = 0 - tp[44][5] = 1 - tp[44][6] = -6 - tp[44][7] = 0 - tp[45][1] = 2 - tp[45][2] = 0 - tp[45][3] = 0 - tp[45][4] = 0 - tp[45][5] = 1 - tp[45][6] = -6 - tp[45][7] = 0 - tp[46][1] = 0 - tp[46][2] = -1 - tp[46][3] = 1 - tp[46][4] = 0 - tp[46][5] = 0 - tp[46][6] = 5 - tp[46][7] = 0 - tp[47][1] = -2 - tp[47][2] = -1 - tp[47][3] = 0 - tp[47][4] = 2 - tp[47][5] = 1 - tp[47][6] = -5 - tp[47][7] = 0 - tp[48][1] = -2 - tp[48][2] = 0 - tp[48][3] = 0 - tp[48][4] = 0 - tp[48][5] = 1 - tp[48][6] = -5 - tp[48][7] = 0 - tp[49][1] = 0 - tp[49][2] = 0 - tp[49][3] = 2 - tp[49][4] = 2 - tp[49][5] = 1 - tp[49][6] = -5 - tp[49][7] = 0 - tp[50][1] = -2 - tp[50][2] = 0 - tp[50][3] = 2 - tp[50][4] = 0 - tp[50][5] = 1 - tp[50][6] = 4 - tp[50][7] = 0 - tp[51][1] = -2 - tp[51][2] = 1 - tp[51][3] = 0 - tp[51][4] = 2 - tp[51][5] = 1 - tp[51][6] = 4 - tp[51][7] = 0 - tp[52][1] = 0 - tp[52][2] = 0 - tp[52][3] = 1 - tp[52][4] = -2 - tp[52][5] = 0 - tp[52][6] = 4 - tp[52][7] = 0 - tp[53][1] = -1 - tp[53][2] = 0 - tp[53][3] = 1 - tp[53][4] = 0 - tp[53][5] = 0 - tp[53][6] = -4 - tp[53][7] = 0 - tp[54][1] = -2 - tp[54][2] = 1 - tp[54][3] = 0 - tp[54][4] = 0 - tp[54][5] = 0 - tp[54][6] = -4 - tp[54][7] = 0 - tp[55][1] = 1 - tp[55][2] = 0 - tp[55][3] = 0 - tp[55][4] = 0 - tp[55][5] = 0 - tp[55][6] = -4 - tp[55][7] = 0 - tp[56][1] = 0 - tp[56][2] = 0 - tp[56][3] = 1 - tp[56][4] = 2 - tp[56][5] = 0 - tp[56][6] = 3 - tp[56][7] = 0 - tp[57][1] = 0 - tp[57][2] = 0 - tp[57][3] = -2 - tp[57][4] = 2 - tp[57][5] = 2 - tp[57][6] = -3 - tp[57][7] = 0 - tp[58][1] = -1 - tp[58][2] = -1 - tp[58][3] = 1 - tp[58][4] = 0 - tp[58][5] = 0 - tp[58][6] = -3 - tp[58][7] = 0 - tp[59][1] = 0 - tp[59][2] = 1 - tp[59][3] = 1 - tp[59][4] = 0 - tp[59][5] = 0 - tp[59][6] = -3 - tp[59][7] = 0 - tp[60][1] = 0 - tp[60][2] = -1 - tp[60][3] = 1 - tp[60][4] = 2 - tp[60][5] = 2 - tp[60][6] = -3 - tp[60][7] = 0 - tp[61][1] = 2 - tp[61][2] = -1 - tp[61][3] = -1 - tp[61][4] = 2 - tp[61][5] = 2 - tp[61][6] = -3 - tp[61][7] = 0 - tp[62][1] = 0 - tp[62][2] = 0 - tp[62][3] = 3 - tp[62][4] = 2 - tp[62][5] = 2 - tp[62][6] = -3 - tp[62][7] = 0 - tp[63][1] = 2 - tp[63][2] = -1 - tp[63][3] = 0 - tp[63][4] = 2 - tp[63][5] = 2 - tp[63][6] = -3 - tp[63][7] = 0 - var S float64 - for i := 1; i < 64; i++ { - S += (tp[i][6] + tp[i][7]) * Sin(D*tp[i][1]+M*tp[i][2]+N*tp[i][3]+F*tp[i][4]+O*tp[i][5]) - } - //P=-17.20*Sin(O)-1.32*Sin(2*280.4665 + 36000.7698*T)-0.23*Sin(2*218.3165 + 481267.8813*T )+0.21*Sin(2*O); +func HJZD(jd float64) float64 { // '黄经章动 + t := (jd - 2451545) / 36525.000 + d := 297.8502042 + 445267.1115168*t - 0.0016300*t*t + t*t*t/545868 - t*t*t*t/113065000 + m := SunM(jd) + n := MoonM(jd) + f := MoonLonX(jd) + o := 125.04452 - 1934.136261*t + 0.0020708*t*t + t*t*t/450000 + tp := [][]float64{{0, 0, 0, 0, 1, -171996, -174.2 * t}, {-2, 0, 0, 2, 2, -13187, -1.6 * t}, {0, 0, 0, 2, 2, -2274, -0.2 * t}, {0, 0, 0, 0, 2, 2062, 0.2 * t}, {0, 1, 0, 0, 0, 1426, -3.4 * t}, {0, 0, 1, 0, 0, 712, 0.1 * t}, {-2, 1, 0, 2, 2, -517, 1.2 * t}, {0, 0, 0, 2, 1, -386, -0.4 * t}, {0, 0, 1, 2, 2, -301, 0}, {-2, -1, 0, 2, 2, 217, -0.5 * t}, {-2, 0, 1, 0, 0, -158, 0}, {-2, 0, 0, 2, 1, 129, 0.1 * t}, {0, 0, -1, 2, 2, 123, 0}, {2, 0, 0, 0, 0, 63, 0}, {0, 0, 1, 0, 1, 63, 0.1 * t}, {2, 0, -1, 2, 2, -59, 0}, {0, 0, -1, 0, 1, -58, -0.1 * t}, {0, 0, 1, 2, 1, -51, 0}, {-2, 0, 2, 0, 0, 48, 0}, {0, 0, -2, 2, 1, 46, 0}, {2, 0, 0, 2, 2, -38, 0}, {0, 0, 2, 2, 2, -31, 0}, {0, 0, 2, 0, 0, 29, 0}, {-2, 0, 1, 2, 2, 29, 0}, {0, 0, 0, 2, 0, 26, 0}, {-2, 0, 0, 2, 0, -22, 0}, {0, 0, -1, 2, 1, 21, 0}, {0, 2, 0, 0, 0, 17, -0.1 * t}, {2, 0, -1, 0, 1, 16, 0}, {-2, 2, 0, 2, 2, -16, 0.1 * t}, {0, 1, 0, 0, 1, -15, 0}, {-2, 0, 1, 0, 1, -13, 0}, {0, -1, 0, 0, 1, -12, 0}, {0, 0, 2, -2, 0, 11, 0}, {2, 0, -1, 2, 1, -10, 0}, {2, 0, 1, 2, 2, -8, 0}, {0, 1, 0, 2, 2, 7, 0}, {-2, 1, 1, 0, 0, -7, 0}, {0, -1, 0, 2, 2, -7, 0}, {2, 0, 0, 2, 1, -7, 0}, {2, 0, 1, 0, 0, 6, 0}, {-2, 0, 2, 2, 2, 6, 0}, {-2, 0, 1, 2, 1, 6, 0}, {2, 0, -2, 0, 1, -6, 0}, {2, 0, 0, 0, 1, -6, 0}, {0, -1, 1, 0, 0, 5, 0}, {-2, -1, 0, 2, 1, -5, 0}, {-2, 0, 0, 0, 1, -5, 0}, {0, 0, 2, 2, 1, -5, 0}, {-2, 0, 2, 0, 1, 4, 0}, {-2, 1, 0, 2, 1, 4, 0}, {0, 0, 1, -2, 0, 4, 0}, {-1, 0, 1, 0, 0, -4, 0}, {-2, 1, 0, 0, 0, -4, 0}, {1, 0, 0, 0, 0, -4, 0}, {0, 0, 1, 2, 0, 3, 0}, {0, 0, -2, 2, 2, -3, 0}, {-1, -1, 1, 0, 0, -3, 0}, {0, 1, 1, 0, 0, -3, 0}, {0, -1, 1, 2, 2, -3, 0}, {2, -1, -1, 2, 2, -3, 0}, {0, 0, 3, 2, 2, -3, 0}, {2, -1, 0, 2, 2, -3, 0}} + var s float64 + for i := 0; i < len(tp); i++ { + s += (tp[i][5] + tp[i][6]) * Sin(d*tp[i][0]+m*tp[i][1]+n*tp[i][2]+f*tp[i][3]+o*tp[i][4]) + } + //P=-17.20*Sin(o)-1.32*Sin(2*280.4665 + 36000.7698*t)-0.23*Sin(2*218.3165 + 481267.8813*t )+0.21*Sin(2*o); //return P/3600; - return (S / 10000) / 3600 + return (s / 10000) / 3600 } /* * 交角章动 */ -func JJZD(JD float64) float64 { //交角章动 - - T := (JD - 2451545) / 36525 - //D = 297.85036 +455267.111480*T - 0.0019142*T*T+ T*T*T/189474; - //M = 357.52772 + 35999.050340*T - 0.0001603*T*T- T*T*T/300000; - //N= 134.96298 + 477198.867398*T + 0.0086972*T*T + T*T*T/56250; - //F = 93.27191 + 483202.017538*T - 0.0036825*T*T + T*T*T/327270; - D := 297.8502042 + 445267.1115168*T - 0.0016300*T*T + T*T*T/545868 - T*T*T*T/113065000 - M := SunM(JD) - N := MoonM(JD) - F := MoonLonX(JD) - O := 125.04452 - 1934.136261*T + 0.0020708*T*T + T*T*T/450000 - tp := make(map[int]map[int]float64) - for i := 1; i < 64; i++ { - tp[i] = make(map[int]float64) - } - tp[1][1] = 0 - tp[1][2] = 0 - tp[1][3] = 0 - tp[1][4] = 0 - tp[1][5] = 1 - tp[1][6] = 92025 - tp[1][7] = 8.9 * T - tp[2][1] = -2 - tp[2][2] = 0 - tp[2][3] = 0 - tp[2][4] = 2 - tp[2][5] = 2 - tp[2][6] = 5736 - tp[2][7] = -3.1 * T - tp[3][1] = 0 - tp[3][2] = 0 - tp[3][3] = 0 - tp[3][4] = 2 - tp[3][5] = 2 - tp[3][6] = 977 - tp[3][7] = -0.5 * T - tp[4][1] = 0 - tp[4][2] = 0 - tp[4][3] = 0 - tp[4][4] = 0 - tp[4][5] = 2 - tp[4][6] = -895 - tp[4][7] = 0.5 * T - tp[5][1] = 0 - tp[5][2] = 1 - tp[5][3] = 0 - tp[5][4] = 0 - tp[5][5] = 0 - tp[5][6] = 54 - tp[5][7] = -0.1 * T - tp[6][1] = 0 - tp[6][2] = 0 - tp[6][3] = 1 - tp[6][4] = 0 - tp[6][5] = 0 - tp[6][6] = -7 - tp[6][7] = 0 - tp[7][1] = -2 - tp[7][2] = 1 - tp[7][3] = 0 - tp[7][4] = 2 - tp[7][5] = 2 - tp[7][6] = 224 - tp[7][7] = -0.6 * T - tp[8][1] = 0 - tp[8][2] = 0 - tp[8][3] = 0 - tp[8][4] = 2 - tp[8][5] = 1 - tp[8][6] = 200 - tp[8][7] = 0 - tp[9][1] = 0 - tp[9][2] = 0 - tp[9][3] = 1 - tp[9][4] = 2 - tp[9][5] = 2 - tp[9][6] = 129 - tp[9][7] = -0.1 * T - tp[10][1] = -2 - tp[10][2] = -1 - tp[10][3] = 0 - tp[10][4] = 2 - tp[10][5] = 2 - tp[10][6] = -95 - tp[10][7] = 0.3 * T - tp[11][1] = -2 - tp[11][2] = 0 - tp[11][3] = 0 - tp[11][4] = 2 - tp[11][5] = 1 - tp[11][6] = -70 - tp[11][7] = 0 - tp[12][1] = 0 - tp[12][2] = 0 - tp[12][3] = -1 - tp[12][4] = 2 - tp[12][5] = 2 - tp[12][6] = -53 - tp[12][7] = 0 - tp[13][1] = 2 - tp[13][2] = 0 - tp[13][3] = 0 - tp[13][4] = 0 - tp[13][5] = 0 - tp[13][6] = 63 - tp[13][7] = 0 - tp[14][1] = 0 - tp[14][2] = 0 - tp[14][3] = 1 - tp[14][4] = 0 - tp[14][5] = 1 - tp[14][6] = -33 - tp[14][7] = 0 - tp[15][1] = 2 - tp[15][2] = 0 - tp[15][3] = -1 - tp[15][4] = 2 - tp[15][5] = 2 - tp[15][6] = 26 - tp[15][7] = 0 - tp[16][1] = 0 - tp[16][2] = 0 - tp[16][3] = -1 - tp[16][4] = 0 - tp[16][5] = 1 - tp[16][6] = 32 - tp[16][7] = 0 - tp[17][1] = 0 - tp[17][2] = 0 - tp[17][3] = 1 - tp[17][4] = 2 - tp[17][5] = 1 - tp[17][6] = 27 - tp[17][7] = 0 - tp[18][1] = 0 - tp[18][2] = 0 - tp[18][3] = -2 - tp[18][4] = 2 - tp[18][5] = 1 - tp[18][6] = -24 - tp[18][7] = 0 - tp[19][1] = 2 - tp[19][2] = 0 - tp[19][3] = 0 - tp[19][4] = 2 - tp[19][5] = 2 - tp[19][6] = 16 - tp[19][7] = 0 - tp[20][1] = 0 - tp[20][2] = 0 - tp[20][3] = 2 - tp[20][4] = 2 - tp[20][5] = 2 - tp[20][6] = 13 - tp[20][7] = 0 - tp[21][1] = -2 - tp[21][2] = 0 - tp[21][3] = 1 - tp[21][4] = 2 - tp[21][5] = 2 - tp[21][6] = -12 - tp[21][7] = 0 - tp[22][1] = 0 - tp[22][2] = 0 - tp[22][3] = -1 - tp[22][4] = 2 - tp[22][5] = 1 - tp[22][6] = -10 - tp[22][7] = 0 - tp[23][1] = 2 - tp[23][2] = 0 - tp[23][3] = -1 - tp[23][4] = 0 - tp[23][5] = 1 - tp[23][6] = -8 - tp[23][7] = 0 - tp[24][1] = -2 - tp[24][2] = 2 - tp[24][3] = 0 - tp[24][4] = 2 - tp[24][5] = 2 - tp[24][6] = 7 - tp[24][7] = 0 - tp[25][1] = 0 - tp[25][2] = 1 - tp[25][3] = 0 - tp[25][4] = 0 - tp[25][5] = 1 - tp[25][6] = 9 - tp[25][7] = 0 - tp[26][1] = -2 - tp[26][2] = 0 - tp[26][3] = 1 - tp[26][4] = 0 - tp[26][5] = 1 - tp[26][6] = 7 - tp[26][7] = 0 - tp[27][1] = 0 - tp[27][2] = -1 - tp[27][3] = 0 - tp[27][4] = 0 - tp[27][5] = 1 - tp[27][6] = 6 - tp[27][7] = 0 - tp[28][1] = 2 - tp[28][2] = 0 - tp[28][3] = -1 - tp[28][4] = 2 - tp[28][5] = 1 - tp[28][6] = 5 - tp[28][7] = 0 - tp[29][1] = 2 - tp[29][2] = 0 - tp[29][3] = 1 - tp[29][4] = 2 - tp[29][5] = 2 - tp[29][6] = 3 - tp[29][7] = 0 - tp[30][1] = 0 - tp[30][2] = 1 - tp[30][3] = 0 - tp[30][4] = 2 - tp[30][5] = 2 - tp[30][6] = -3 - tp[30][7] = 0 - tp[31][1] = 0 - tp[31][2] = -1 - tp[31][3] = 0 - tp[31][4] = 2 - tp[31][5] = 2 - tp[31][6] = 3 - tp[31][7] = 0 - tp[32][1] = 2 - tp[32][2] = 0 - tp[32][3] = 0 - tp[32][4] = 2 - tp[32][5] = 1 - tp[32][6] = 3 - tp[32][7] = 0 - tp[33][1] = -2 - tp[33][2] = 0 - tp[33][3] = 2 - tp[33][4] = 2 - tp[33][5] = 2 - tp[33][6] = -3 - tp[33][7] = 0 - tp[34][1] = -2 - tp[34][2] = 0 - tp[34][3] = 1 - tp[34][4] = 2 - tp[34][5] = 1 - tp[34][6] = -3 - tp[34][7] = 0 - tp[35][1] = 2 - tp[35][2] = 0 - tp[35][3] = -2 - tp[35][4] = 0 - tp[35][5] = 1 - tp[35][6] = 3 - tp[35][7] = 0 - tp[36][1] = 2 - tp[36][2] = 0 - tp[36][3] = 0 - tp[36][4] = 0 - tp[36][5] = 1 - tp[36][6] = 3 - tp[36][7] = 0 - tp[37][1] = -2 - tp[37][2] = -1 - tp[37][3] = 0 - tp[37][4] = 2 - tp[37][5] = 1 - tp[37][6] = 3 - tp[37][7] = 0 - tp[38][1] = -2 - tp[38][2] = 0 - tp[38][3] = 0 - tp[38][4] = 0 - tp[38][5] = 1 - tp[38][6] = 3 - tp[38][7] = 0 - tp[39][1] = 0 - tp[39][2] = 0 - tp[39][3] = 2 - tp[39][4] = 2 - tp[39][5] = 1 - tp[39][6] = 3 - tp[39][7] = 0 - var S float64 = 0 - for i := 1; i < 40; i++ { - S += (tp[i][6] + tp[i][7]) * Cos(D*tp[i][1]+M*tp[i][2]+N*tp[i][3]+F*tp[i][4]+O*tp[i][5]) +func JJZD(jd float64) float64 { //交角章动 + t := (jd - 2451545) / 36525 + //d = 297.85036 +455267.111480*t - 0.0019142*t*t+ t*t*t/189474; + //m = 357.52772 + 35999.050340*t - 0.0001603*t*t- t*t*t/300000; + //n= 134.96298 + 477198.867398*t + 0.0086972*t*t + t*t*t/56250; + //f = 93.27191 + 483202.017538*t - 0.0036825*t*t + t*t*t/327270; + d := 297.8502042 + 445267.1115168*t - 0.0016300*t*t + t*t*t/545868 - t*t*t*t/113065000 + m := SunM(jd) + n := MoonM(jd) + f := MoonLonX(jd) + o := 125.04452 - 1934.136261*t + 0.0020708*t*t + t*t*t/450000 + tp := [][]float64{{0, 0, 0, 0, 1, 92025, 8.9 * t}, {-2, 0, 0, 2, 2, 5736, -3.1 * t}, {0, 0, 0, 2, 2, 977, -0.5 * t}, {0, 0, 0, 0, 2, -895, 0.5 * t}, {0, 1, 0, 0, 0, 54, -0.1 * t}, {0, 0, 1, 0, 0, -7, 0}, {-2, 1, 0, 2, 2, 224, -0.6 * t}, {0, 0, 0, 2, 1, 200, 0}, {0, 0, 1, 2, 2, 129, -0.1 * t}, {-2, -1, 0, 2, 2, -95, 0.3 * t}, {-2, 0, 0, 2, 1, -70, 0}, {0, 0, -1, 2, 2, -53, 0}, {2, 0, 0, 0, 0, 63, 0}, {0, 0, 1, 0, 1, -33, 0}, {2, 0, -1, 2, 2, 26, 0}, {0, 0, -1, 0, 1, 32, 0}, {0, 0, 1, 2, 1, 27, 0}, {0, 0, -2, 2, 1, -24, 0}, {2, 0, 0, 2, 2, 16, 0}, {0, 0, 2, 2, 2, 13, 0}, {-2, 0, 1, 2, 2, -12, 0}, {0, 0, -1, 2, 1, -10, 0}, {2, 0, -1, 0, 1, -8, 0}, {-2, 2, 0, 2, 2, 7, 0}, {0, 1, 0, 0, 1, 9, 0}, {-2, 0, 1, 0, 1, 7, 0}, {0, -1, 0, 0, 1, 6, 0}, {2, 0, -1, 2, 1, 5, 0}, {2, 0, 1, 2, 2, 3, 0}, {0, 1, 0, 2, 2, -3, 0}, {0, -1, 0, 2, 2, 3, 0}, {2, 0, 0, 2, 1, 3, 0}, {-2, 0, 2, 2, 2, -3, 0}, {-2, 0, 1, 2, 1, -3, 0}, {2, 0, -2, 0, 1, 3, 0}, {2, 0, 0, 0, 1, 3, 0}, {-2, -1, 0, 2, 1, 3, 0}, {-2, 0, 0, 0, 1, 3, 0}, {0, 0, 2, 2, 1, 3, 0}} + var s float64 = 0 + for i := 0; i < len(tp); i++ { + s += (tp[i][5] + tp[i][6]) * Cos(d*tp[i][0]+m*tp[i][1]+n*tp[i][2]+f*tp[i][3]+o*tp[i][4]) } - return S / 10000 / 3600 + return s / 10000 / 3600 } /* - @name 太阳几何黄经 +@name 太阳几何黄经 */ func SunLo(jd float64) float64 { T := (jd - 2451545) / 365250 @@ -806,7 +82,7 @@ func SunM(JD float64) float64 { } /* - @name 地球偏心率 +@name 地球偏心率 */ func Earthe(JD float64) float64 { //'地球偏心率 T := (JD - 2451545) / 36525 @@ -841,6 +117,10 @@ func SunApparentRa(JD float64) float64 { // '太阳视赤经 return LoToRa(JD, SunApparentLo(JD), 0) } +func SunApparentRaDec(JD float64) (float64, float64) { + return LoBoToRaDec(JD, SunApparentLo(JD), 0) +} + func SunTrueRa(JD float64) float64 { //'太阳真赤经 sitas := Sita(JD) @@ -965,54 +245,47 @@ func RDJL(jd float64) float64 { //ri di ju li return (1.000001018 * (1 - e*e) / (1 + e*Cos(f+m))) } -func GetOneYearMoon(year float64) map[int]float64 { +func GetMoonLoops(year float64, loop int) []float64 { var start float64 - var tmp1, tmp float64 - moon := make(map[int]float64) + var newMoon, tmp float64 + moon := make([]float64, loop) if year < 6000 { start = year + 11.00/12.00 + 5.00/30.00/12.00 } else { start = year + 9.00/12.00 + 5.00/30.00/12.00 } i := 1 - for j := 1; j < 17; j++ { + for j := 0; j < loop; j++ { if year > 3000 { - tmp1 = TD2UT(CalcMoonSH(start+float64(i-1)/12.5, 0)+8.0/24.0, false) + newMoon = TD2UT(CalcMoonSH(start+float64(i-1)/12.5, 0)+8.0/24.0, false) } else { - tmp1 = TD2UT(CalcMoonS(start+float64(i-1)/12.5, 0)+8.0/24.0, false) + newMoon = TD2UT(CalcMoonS(start+float64(i-1)/12.5, 0)+8.0/24.0, false) } if i != 1 { - if tmp1 == tmp { + if newMoon == tmp { j-- i++ continue } } - moon[j] = tmp1 + moon[j] = newMoon tmp = moon[j] i++ // echo DateCalc(moon[i])."
"; } return moon } -func GetOneYearJQ(year int) []float64 { + +func GetJieqiLoops(year, loop int) []float64 { start := 270 - var years int - jq := make([]float64, 26) - for i := 1; i < 26; i++ { + jq := make([]float64, loop) + for i := 1; i <= loop; i++ { angle := start + 15*(i-1) if angle > 360 { angle -= 360 } - if i > 1 { - years = year + 1 - } else { - years = year - } - jq[i] = GetJQTime(years, angle) + 8.0/24.0 - // echo DateCalc(jq[i])."
"; + jq[i-1] = GetJQTime(year+int(math.Ceil(float64(i-1)/24.000)), angle) + 8.0/24.0 } - jq[0] = jq[1] return jq } diff --git a/basic/sun_test.go b/basic/sun_test.go index 817e240..90c62bb 100644 --- a/basic/sun_test.go +++ b/basic/sun_test.go @@ -1,13 +1,15 @@ package basic import ( + "b612.me/astro/tools" "fmt" + "math" "testing" "time" ) func Test_Jq(t *testing.T) { - data := GetOneYearJQ(2019) + data := GetJieqiLoops(2019, 24) for i := 1; i < 25; i++ { fmt.Println(JDE2Date(data[i])) } @@ -17,11 +19,59 @@ func Test_Jq(t *testing.T) { //fmt.Println(HSunApparentLo(date)) } +func TestZD(t *testing.T) { + jde := 2452982.9872345612 + zd := HJZD(jde) + fmt.Println(zd) + if zd != -0.003746747950462434 { + t.Fatal("not equal") + } + zd = JJZD(jde) + fmt.Println(zd) + if zd != 0.001513453926274198 { + t.Fatal("not equal") + } +} + func Test_SunLo(t *testing.T) { fmt.Printf("%.14f\n", HSunTrueLo(2458840.0134162)) fmt.Printf("%.14f", HSunApparentLo(2458840.0134162)) } +func Test_SunDiff(t *testing.T) { + n := JDECalc(2000, 1, 1) + var maxRa, maxDec, maxLo float64 + for i := float64(0); i < 365.2422*30; i++ { + tLo := HSunApparentLo(n + i) + tRa, tDec := HSunApparentRaDec(n + i) + fRa, fDec := SunApparentRaDec(n + i) + fLo := SunApparentLo(n + i) + tmp := tools.Limit360(math.Abs(tRa - fRa)) + if tmp > 300 { + tmp = 360 - tmp + } + if tmp > maxRa { + maxRa = tmp + } + tmp = tools.Limit360(math.Abs(tDec - fDec)) + if tmp > 300 { + tmp = 360 - tmp + } + if tmp > maxDec { + maxDec = tmp + } + + tmp = tools.Limit360(math.Abs(tLo - fLo)) + if tmp > 300 { + tmp = 360 - tmp + } + if tmp > maxLo { + maxLo = tmp + } + } + fmt.Printf("%.15f %.15f %.15f\n", maxRa*3600, maxDec*3600, maxLo*3600) +} + func Benchmark_SunRise(b *testing.B) { jde := GetNowJDE() for i := 0; i < b.N; i++ { diff --git a/calendar/chinese.go b/calendar/chinese.go index 20153d4..d9f2356 100644 --- a/calendar/chinese.go +++ b/calendar/chinese.go @@ -98,3 +98,144 @@ func WuHou(year, term int) time.Time { zone := time.FixedZone("CST", 8*3600) return basic.JDE2DateByZone(calcJde, zone, false) } + +// RapidLunarToSolar 农历转公历(快速查表法) +// 传入 农历年份,月,日,是否闰月 +// 传出 公历时间 +// 农历年份用公历年份代替,但是岁首需要使用农历岁首 +// 例:计算己亥猪年腊月三十日对应的公历(即2020年1月24日) +// 由于农历还未到鼠年,故应当传入Solar(2019,12,30,false) +// 按现行农历GB/T 33661-2017算法计算,推荐使用年限为[1929-3000]年 +// 对于东八区[1900-2400]年的查询,会使用查表法加快计算速度 +// 古代由于定朔定气误差此处计算会与古时不符 +func RapidLunarToSolar(year, month, day int, leap bool) time.Time { + if year < 1900 || year > 2400 { + jde := basic.GetSolar(year, month, day, leap, 8.0/24.0) + zone := time.FixedZone("CST", 8*3600) + return basic.JDE2DateByZone(jde, zone, true) + } + return rapidSolar(year, month, day, leap) +} + +// RapidSolarToLunar 公历转农历(快速查表法) +// 传入 公历年月日 +// 返回 农历月,日,是否闰月以及文字描述 +// 忽略时区,日期一律按北京时间计算 +// 按现行农历GB/T 33661-2017算法计算,推荐使用年限为[1929-3000]年 +// 古代由于定朔定气误差此处计算会与古时不符 +// 对于东八区[1900-2400]年的查询,会使用查表法加快计算速度 +func RapidSolarToLunar(date time.Time) (int, int, bool, string) { + if date.Year() < 1900 || date.Year() > 2400 { + return basic.GetLunar(date.Year(), int(date.Month()), date.Day(), 8.0/24.0) + } + return rapidLunar(date.Year(), int(date.Month()), date.Day()) +} + +func rapidLunar(year, month, day int) (int, int, bool, string) { + var upper = []uint16{32274, 52242, 41001, 30036, 49204, 36918, 25882, 46101, 34854, 22674, 43026, 31145, 51241, 38964, 26997, 47149, 36885, 23717, 44069, 34258, 53266, 41001, 29036, 49178, 37915, 24875, 46090, 34853, 23698, 43026, 31129, 50229, 38970, 26971, 47126, 36874, 24804, 44068, 32242, 52274, 41013, 28086, 48173, 37909, 25898, 46089, 34852, 22706, 43050, 30189, 50203, 38957, 27989, 47123, 35881, 24788, 45076, 32298, 51258, 40986, 29099, 48170, 37906, 25897, 46121, 34836, 21754, 42038, 31190, 50197, 38949, 27986, 48146, 35881, 23860, 44084, 32309, 51245, 39981, 29093, 49189, 37906, 25897, 46121, 35500, 53274, 42011, 30123, 50218, 38949, 27986, 48146, 36889, 23770, 43066, 32282, 52246, 39978, 29028, 49188, 37938, 24885, 45109, 33846, 22678, 42005, 30186, 51209, 39972, 26994, 47146, 35885, 23853, 43051, 32341, 52242, 41001, 29076, 49172, 37930, 25885, 45082, 33835, 22675, 43026, 30121, 50217, 38964, 27002, 46133, 35862, 23770, 44069, 32466, 52242, 41001, 29108, 48180, 36917, 24950, 45101, 33813, 22674, 43026, 31209, 50217, 38954, 26989, 47131, 34859, 23765, 44068, 34322, 52242, 40985, 29082, 48186, 36890, 24874, 45098, 34852, 21746, 42034, 30197, 50229, 37942, 26966, 47125, 35881, 23828, 44052, 32298, 52266, 39981, 28077, 48171, 37909, 24873, 45097, 34836, 22762, 42010, 30172, 50202, 38955, 26963, 47122, 35881, 24852, 43060, 31290, 51253, 39990, 28058, 48149, 37906, 25897, 45097, 33844, 21686, 42037, 30198, 50221, 39957, 29010, 48146, 36905, 24884, 45098, 32365, 52251, 41003, 30101, 49188, 38930, 26905, 47125, 34842, 22747, 43034, 31210, 50218, 39956, 28018, 48170, 35893, 23866, 44086, 34518, 52245, 41001, 30100, 50196, 37930, 25973, 46124, 34861, 22677, 43029, 31209, 51241, 39956, 28010, 48154, 36892, 23853, 44058, 34507, 53266, 41001, 30100, 49204, 37946, 25946, 45110, 34838, 23754, 43018, 31208, 51240, 39988, 27061, 47149, 35893, 24854, 44053, 34442, 53265, 42024, 29098, 49194, 37933, 25965, 45099, 34837, 23753, 44049, 31192, 51220, 39962, 28059, 47126, 35882, 24852, 45074, 31785, 21652, 41012, 29114, 48181, 37910, 25962, 46121, 34834, 22761, 43049, 31220, 50220, 38957, 28053, 48139, 36901, 25874, 46098, 35433, 53273, 42010, 30125, 50202, 38922, 26917, 47140, 36882, 23769, 43065, 31226, 51254, 39958, 29002, 49162, 37924, 24882, 45106, 34421, 53293, 41005, 30165, 50197, 39945, 26980, 47140, 35882, 23797, 43053, 31277, 51243, 40981, 29001, 49161, 37908, 25898, 45082, 34523, 53270, 42026, 30098, 50194, 38953, 27988, 46132, 34874, 23770, 44054, 31210, 51237, 40978, 29097, 48169, 36916, 24950, 45101, 31797, 21605, 42021, 31186, 50194, 38953, 26988, 47130, 34859, 22765, 44042, 32293, 51236, 40978, 29081, 48185, 35898, 24859, 45078, 34826, 21669, 42020, 30130, 50226, 37941, 25974, 46125, 35861, 22762, 44041, 32228, 52260, 39978, 28077, 48157, 36909, 24853, 45075, 33833, 22676, 43028, 31146, 50234, 39962, 26987, 47146, 36882, 24809, 44073, 34260, 52276, 41014, 29082, 49173, 37926, 26898, 46098, 35497, 54313, 43060, 30197, 50221, 38957, 28005, 47141, 36882, 24809, 45097, 32300, 52250, 40987, 29101, 48170, 37925, 26898, 47122, 34841, 22746, 42042, 31195, 50198, 38954, 28004, 48164, 35890, 23861, 44085, 32310, 51245, 40981, 29098, 50185, 37924, 25970, 46122, 34861, 21614, 42029, 31189, 51218, 38953, 27988, 48148, 36906, 23837, 44058, 32299, 52266, 40978, 29097, 49193, 38932, 24954, 45110, 33846, 22682, 42021, 31186, 51218, 39977, 26996, 47156, 35893, 23862, 43053, 32405, 52261, 42002, 29097, 49193, 37932, 25901, 45083, 33835, 22677, 43044, 31122, 51218, 39961, 27994} + var lower = []uint8{218, 184, 92, 154, 152, 84, 170, 168, 180, 186, 184, 54, 52, 148, 82, 84, 168, 180, 108, 110, 108, 44, 150, 148, 80, 106, 216, 92, 94, 92, 44, 40, 148, 82, 180, 216, 220, 184, 90, 84, 40, 148, 84, 168, 182, 116, 180, 86, 84, 42, 40, 84, 106, 104, 108, 174, 172, 84, 84, 168, 84, 212, 216, 92, 92, 152, 76, 84, 170, 168, 180, 186, 180, 52, 154, 148, 74, 80, 168, 180, 108, 108, 46, 44, 150, 148, 80, 104, 216, 92, 94, 92, 44, 148, 148, 202, 176, 216, 218, 184, 88, 42, 40, 148, 170, 168, 182, 116, 180, 86, 84, 40, 84, 84, 106, 232, 108, 174, 172, 76, 42, 168, 84, 106, 216, 92, 56, 152, 76, 76, 168, 212, 180, 186, 180, 52, 150, 148, 72, 168, 104, 180, 182, 108, 46, 44, 148, 74, 72, 104, 108, 220, 94, 92, 44, 148, 148, 200, 216, 184, 184, 92, 88, 42, 40, 148, 170, 168, 180, 186, 180, 86, 84, 40, 84, 84, 104, 116, 108, 172, 78, 76, 166, 168, 84, 106, 216, 92, 156, 88, 76, 72, 168, 212, 180, 184, 58, 52, 84, 74, 72, 164, 104, 116, 182, 108, 44, 150, 148, 74, 72, 88, 108, 220, 92, 46, 44, 148, 74, 168, 212, 180, 184, 92, 88, 40, 148, 84, 170, 168, 180, 186, 180, 52, 42, 168, 84, 170, 104, 116, 108, 172, 46, 44, 164, 84, 212, 106, 216, 92, 92, 88, 44, 164, 164, 212, 218, 184, 186, 180, 84, 42, 72, 164, 180, 108, 182, 108, 172, 86, 84, 40, 84, 84, 108, 110, 92, 174, 172, 84, 42, 168, 212, 218, 184, 92, 172, 168, 84, 84, 168, 212, 180, 184, 86, 52, 150, 164, 84, 170, 104, 116, 182, 108, 46, 44, 164, 82, 212, 216, 108, 220, 92, 44, 40, 148, 164, 212, 218, 184, 184, 90, 84, 42, 40, 164, 180, 108, 116, 182, 172, 84, 42, 40, 84, 84, 108, 110, 92, 172, 86, 84, 42, 168, 212, 218, 184, 92, 154, 152, 84, 170, 168, 180, 116, 184, 54, 52, 148, 74, 80, 168, 180, 108, 174, 108, 44, 150, 148, 80, 106, 216, 108, 220, 92, 44, 40, 148, 82, 180, 216, 92, 184, 90, 84, 40, 148, 148, 168, 182, 116, 182, 172, 84, 42, 40, 84, 170, 104, 108, 174, 172, 84, 84, 168, 84, 212, 216, 92, 92, 154, 152, 84, 170, 168, 180, 186, 180, 54, 52, 148, 74, 80, 168, 180, 108, 108, 46, 44, 150, 148, 80, 104, 216, 92, 94, 92, 44, 148, 148, 74, 176, 216, 218, 184, 88, 42, 40, 148, 84, 168, 182, 116, 180, 86, 84, 40, 148, 84, 106, 232, 108, 174, 172, 76, 42, 168, 84, 212, 216, 92, 92, 152, 76, 72, 168, 212, 180, 186, 180, 52, 150, 148, 72, 168, 104, 180, 108, 108, 46, 44, 148, 74, 72, 104, 108, 220, 94, 92, 44, 148} + if year < 1900 || year > 2400 { + return 0, 0, false, "超过日期限制" + } + useGoto := false +recalc: + idx := year - 1900 + magic := int32(upper[idx])<<8 + int32(lower[idx]) + springMonth := (magic&0x800000)>>23 + 1 + springDay := (magic & 0x7FFFFF) >> 18 + if springMonth == int32(month) && springDay == int32(day) { + return 1, 1, false, "正月初一" + } + if !useGoto && (springMonth > int32(month) || (springMonth == int32(month) && springDay > int32(day))) { + year-- + useGoto = true + goto recalc + } + calcYear := year + if useGoto { + calcYear++ + } + target := time.Date(calcYear, time.Month(month), day, 0, 0, 0, 0, time.Local) + spring := time.Date(year, time.Month(int(springMonth)), int(springDay), 0, 0, 0, 0, time.Local) + diffDay := int(target.Sub(spring).Hours() / 24) + lunarMonth := 1 + totalDay := 0 + isLeap := false + leapMonth := int(uint8(magic>>14) & 0xF) + strmonth := []string{"十", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊"} + strday := []string{"初", "十", "廿", "三"} + for i := 0; i < 13; i++ { + var dayofLunar = 29 + tmp := uint8(magic&0x3FFE>>(13-i)) & 1 + if tmp == 1 { + dayofLunar++ + } + if totalDay+dayofLunar > diffDay { + var result string + if isLeap { + result += "闰" + } + if lunarMonth == 1 { + result += "正月" + } else { + result += strmonth[lunarMonth] + "月" + } + lday := diffDay - totalDay + 1 + if lday == 20 { + result += "二十" + } else if lday == 10 { + result += "初十" + } else { + result += strday[lday/10] + strmonth[lday%10] + } + return lunarMonth, lday, isLeap, result + } + totalDay += dayofLunar + lunarMonth++ + if lunarMonth-leapMonth == 1 && !isLeap { + isLeap = true + lunarMonth-- + } else { + isLeap = false + } + } + return 0, 0, false, "无法获取农历信息" +} + +func rapidSolar(year, month, day int, isLeap bool) time.Time { + var upper = []uint16{32274, 52242, 41001, 30036, 49204, 36918, 25882, 46101, 34854, 22674, 43026, 31145, 51241, 38964, 26997, 47149, 36885, 23717, 44069, 34258, 53266, 41001, 29036, 49178, 37915, 24875, 46090, 34853, 23698, 43026, 31129, 50229, 38970, 26971, 47126, 36874, 24804, 44068, 32242, 52274, 41013, 28086, 48173, 37909, 25898, 46089, 34852, 22706, 43050, 30189, 50203, 38957, 27989, 47123, 35881, 24788, 45076, 32298, 51258, 40986, 29099, 48170, 37906, 25897, 46121, 34836, 21754, 42038, 31190, 50197, 38949, 27986, 48146, 35881, 23860, 44084, 32309, 51245, 39981, 29093, 49189, 37906, 25897, 46121, 35500, 53274, 42011, 30123, 50218, 38949, 27986, 48146, 36889, 23770, 43066, 32282, 52246, 39978, 29028, 49188, 37938, 24885, 45109, 33846, 22678, 42005, 30186, 51209, 39972, 26994, 47146, 35885, 23853, 43051, 32341, 52242, 41001, 29076, 49172, 37930, 25885, 45082, 33835, 22675, 43026, 30121, 50217, 38964, 27002, 46133, 35862, 23770, 44069, 32466, 52242, 41001, 29108, 48180, 36917, 24950, 45101, 33813, 22674, 43026, 31209, 50217, 38954, 26989, 47131, 34859, 23765, 44068, 34322, 52242, 40985, 29082, 48186, 36890, 24874, 45098, 34852, 21746, 42034, 30197, 50229, 37942, 26966, 47125, 35881, 23828, 44052, 32298, 52266, 39981, 28077, 48171, 37909, 24873, 45097, 34836, 22762, 42010, 30172, 50202, 38955, 26963, 47122, 35881, 24852, 43060, 31290, 51253, 39990, 28058, 48149, 37906, 25897, 45097, 33844, 21686, 42037, 30198, 50221, 39957, 29010, 48146, 36905, 24884, 45098, 32365, 52251, 41003, 30101, 49188, 38930, 26905, 47125, 34842, 22747, 43034, 31210, 50218, 39956, 28018, 48170, 35893, 23866, 44086, 34518, 52245, 41001, 30100, 50196, 37930, 25973, 46124, 34861, 22677, 43029, 31209, 51241, 39956, 28010, 48154, 36892, 23853, 44058, 34507, 53266, 41001, 30100, 49204, 37946, 25946, 45110, 34838, 23754, 43018, 31208, 51240, 39988, 27061, 47149, 35893, 24854, 44053, 34442, 53265, 42024, 29098, 49194, 37933, 25965, 45099, 34837, 23753, 44049, 31192, 51220, 39962, 28059, 47126, 35882, 24852, 45074, 31785, 21652, 41012, 29114, 48181, 37910, 25962, 46121, 34834, 22761, 43049, 31220, 50220, 38957, 28053, 48139, 36901, 25874, 46098, 35433, 53273, 42010, 30125, 50202, 38922, 26917, 47140, 36882, 23769, 43065, 31226, 51254, 39958, 29002, 49162, 37924, 24882, 45106, 34421, 53293, 41005, 30165, 50197, 39945, 26980, 47140, 35882, 23797, 43053, 31277, 51243, 40981, 29001, 49161, 37908, 25898, 45082, 34523, 53270, 42026, 30098, 50194, 38953, 27988, 46132, 34874, 23770, 44054, 31210, 51237, 40978, 29097, 48169, 36916, 24950, 45101, 31797, 21605, 42021, 31186, 50194, 38953, 26988, 47130, 34859, 22765, 44042, 32293, 51236, 40978, 29081, 48185, 35898, 24859, 45078, 34826, 21669, 42020, 30130, 50226, 37941, 25974, 46125, 35861, 22762, 44041, 32228, 52260, 39978, 28077, 48157, 36909, 24853, 45075, 33833, 22676, 43028, 31146, 50234, 39962, 26987, 47146, 36882, 24809, 44073, 34260, 52276, 41014, 29082, 49173, 37926, 26898, 46098, 35497, 54313, 43060, 30197, 50221, 38957, 28005, 47141, 36882, 24809, 45097, 32300, 52250, 40987, 29101, 48170, 37925, 26898, 47122, 34841, 22746, 42042, 31195, 50198, 38954, 28004, 48164, 35890, 23861, 44085, 32310, 51245, 40981, 29098, 50185, 37924, 25970, 46122, 34861, 21614, 42029, 31189, 51218, 38953, 27988, 48148, 36906, 23837, 44058, 32299, 52266, 40978, 29097, 49193, 38932, 24954, 45110, 33846, 22682, 42021, 31186, 51218, 39977, 26996, 47156, 35893, 23862, 43053, 32405, 52261, 42002, 29097, 49193, 37932, 25901, 45083, 33835, 22677, 43044, 31122, 51218, 39961, 27994} + var lower = []uint8{218, 184, 92, 154, 152, 84, 170, 168, 180, 186, 184, 54, 52, 148, 82, 84, 168, 180, 108, 110, 108, 44, 150, 148, 80, 106, 216, 92, 94, 92, 44, 40, 148, 82, 180, 216, 220, 184, 90, 84, 40, 148, 84, 168, 182, 116, 180, 86, 84, 42, 40, 84, 106, 104, 108, 174, 172, 84, 84, 168, 84, 212, 216, 92, 92, 152, 76, 84, 170, 168, 180, 186, 180, 52, 154, 148, 74, 80, 168, 180, 108, 108, 46, 44, 150, 148, 80, 104, 216, 92, 94, 92, 44, 148, 148, 202, 176, 216, 218, 184, 88, 42, 40, 148, 170, 168, 182, 116, 180, 86, 84, 40, 84, 84, 106, 232, 108, 174, 172, 76, 42, 168, 84, 106, 216, 92, 56, 152, 76, 76, 168, 212, 180, 186, 180, 52, 150, 148, 72, 168, 104, 180, 182, 108, 46, 44, 148, 74, 72, 104, 108, 220, 94, 92, 44, 148, 148, 200, 216, 184, 184, 92, 88, 42, 40, 148, 170, 168, 180, 186, 180, 86, 84, 40, 84, 84, 104, 116, 108, 172, 78, 76, 166, 168, 84, 106, 216, 92, 156, 88, 76, 72, 168, 212, 180, 184, 58, 52, 84, 74, 72, 164, 104, 116, 182, 108, 44, 150, 148, 74, 72, 88, 108, 220, 92, 46, 44, 148, 74, 168, 212, 180, 184, 92, 88, 40, 148, 84, 170, 168, 180, 186, 180, 52, 42, 168, 84, 170, 104, 116, 108, 172, 46, 44, 164, 84, 212, 106, 216, 92, 92, 88, 44, 164, 164, 212, 218, 184, 186, 180, 84, 42, 72, 164, 180, 108, 182, 108, 172, 86, 84, 40, 84, 84, 108, 110, 92, 174, 172, 84, 42, 168, 212, 218, 184, 92, 172, 168, 84, 84, 168, 212, 180, 184, 86, 52, 150, 164, 84, 170, 104, 116, 182, 108, 46, 44, 164, 82, 212, 216, 108, 220, 92, 44, 40, 148, 164, 212, 218, 184, 184, 90, 84, 42, 40, 164, 180, 108, 116, 182, 172, 84, 42, 40, 84, 84, 108, 110, 92, 172, 86, 84, 42, 168, 212, 218, 184, 92, 154, 152, 84, 170, 168, 180, 116, 184, 54, 52, 148, 74, 80, 168, 180, 108, 174, 108, 44, 150, 148, 80, 106, 216, 108, 220, 92, 44, 40, 148, 82, 180, 216, 92, 184, 90, 84, 40, 148, 148, 168, 182, 116, 182, 172, 84, 42, 40, 84, 170, 104, 108, 174, 172, 84, 84, 168, 84, 212, 216, 92, 92, 154, 152, 84, 170, 168, 180, 186, 180, 54, 52, 148, 74, 80, 168, 180, 108, 108, 46, 44, 150, 148, 80, 104, 216, 92, 94, 92, 44, 148, 148, 74, 176, 216, 218, 184, 88, 42, 40, 148, 84, 168, 182, 116, 180, 86, 84, 40, 148, 84, 106, 232, 108, 174, 172, 76, 42, 168, 84, 212, 216, 92, 92, 152, 76, 72, 168, 212, 180, 186, 180, 52, 150, 148, 72, 168, 104, 180, 108, 108, 46, 44, 148, 74, 72, 104, 108, 220, 94, 92, 44, 148} + if year < 1900 || year > 2400 { + return time.Time{} + } + idx := year - 1900 + magic := int32(upper[idx])<<8 + int32(lower[idx]) + springMonth := (magic&0x800000)>>23 + 1 + springDay := (magic & 0x7FFFFF) >> 18 + spring := time.Date(year, time.Month(int(springMonth)), int(springDay), 0, 0, 0, 0, time.Local) + lunarMonth := 1 + totalDay := 0 + leap := false + leapMonth := int(uint8(magic>>14) & 0xF) + for i := 0; i < 13; i++ { + if lunarMonth == month && isLeap == leap { + target := spring.AddDate(0, 0, totalDay+day-1) + return target + } + + var dayofLunar = 29 + tmp := uint8(magic&0x3FFE>>(13-i)) & 1 + if tmp == 1 { + dayofLunar++ + } + totalDay += dayofLunar + lunarMonth++ + if lunarMonth-leapMonth == 1 && !leap { + leap = true + lunarMonth-- + } else { + leap = false + } + } + return time.Time{} +} diff --git a/calendar/chinese_test.go b/calendar/chinese_test.go index 84ce190..18f9ae4 100644 --- a/calendar/chinese_test.go +++ b/calendar/chinese_test.go @@ -3,6 +3,7 @@ package calendar import ( "fmt" "testing" + "time" ) type lunarSolar struct { @@ -37,7 +38,7 @@ func Test_ChineseCalendar(t *testing.T) { } for _, v := range testData { var lyear int = v.Year - lmonth, lday, leap, desp := Lunar(v.Year, v.Month, v.Day, 8.0) + lmonth, lday, leap, desp := SolarToLunar(time.Date(v.Year, time.Month(v.Month), v.Day, 0, 0, 0, 0, time.Local)) if lmonth > v.Month { lyear-- } @@ -46,7 +47,7 @@ func Test_ChineseCalendar(t *testing.T) { t.Fatal(v, lyear, lmonth, lday, leap, desp) } - date := Solar(v.Lyear, v.Lmonth, v.Lday, v.Leap, 8.0) + date := LunarToSolar(v.Lyear, v.Lmonth, v.Lday, v.Leap) if date.Year() != v.Year || int(date.Month()) != v.Month || date.Day() != v.Day { t.Fatal(v, date) }