astro/calendar/chinese.go

239 lines
19 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package calendar
import (
"time"
"b612.me/astro/basic"
)
const (
JQ_春分 = 15 * iota
JQ_清明
JQ_谷雨
JQ_立夏
JQ_小满
JQ_芒种
JQ_夏至
JQ_小暑
JQ_大暑
JQ_立秋
JQ_处暑
JQ_白露
JQ_秋分
JQ_寒露
JQ_霜降
JQ_立冬
JQ_小雪
JQ_大雪
JQ_冬至
JQ_小寒
JQ_大寒
JQ_立春
JQ_雨水
JQ_惊蛰
)
// Lunar 公历转农历
// 传入 公历年月日,时区
// 返回 农历月,日,是否闰月以及文字描述
// 按现行农历GB/T 33661-2017算法计算推荐使用年限为[1929-3000]年
// 古代由于定朔定气误差此处计算会与古时不符
func Lunar(year, month, day int, timezone float64) (int, int, bool, string) {
return basic.GetLunar(year, month, day, timezone/24.0)
}
// Solar 农历转公历
// 传入 农历年份,月,日,是否闰月,时区
// 传出 公历时间
// 农历年份用公历年份代替,但是岁首需要使用农历岁首
// 例计算己亥猪年腊月三十日对应的公历即2020年1月24日
// 由于农历还未到鼠年故应当传入Solar(2019,12,30,false)
// 按现行农历GB/T 33661-2017算法计算推荐使用年限为[1929-3000]年
// 古代由于定朔定气误差此处计算会与古时不符
func Solar(year, month, day int, leap bool, timezone float64) time.Time {
jde := basic.GetSolar(year, month, day, leap, timezone/24.0)
zone := time.FixedZone("CST", int(timezone*3600))
return basic.JDE2DateByZone(jde, zone, true)
}
// SolarToLunar 公历转农历
// 传入 公历年月日
// 返回 农历月,日,是否闰月以及文字描述
// 忽略时区,日期一律按北京时间计算
// 按现行农历GB/T 33661-2017算法计算推荐使用年限为[1929-3000]年
// 古代由于定朔定气误差此处计算会与古时不符
func SolarToLunar(date time.Time) (int, int, bool, string) {
return basic.GetLunar(date.Year(), int(date.Month()), date.Day(), 8.0/24.0)
}
// LunarToSolar 农历转公历
// 传入 农历年份,月,日,是否闰月
// 传出 公历时间
// 农历年份用公历年份代替,但是岁首需要使用农历岁首
// 例计算己亥猪年腊月三十日对应的公历即2020年1月24日
// 由于农历还未到鼠年故应当传入Solar(2019,12,30,false)
// 按现行农历GB/T 33661-2017算法计算推荐使用年限为[1929-3000]年
// 古代由于定朔定气误差此处计算会与古时不符
func LunarToSolar(year, month, day int, leap bool) time.Time {
jde := basic.GetSolar(year, month, day, leap, 8.0/24.0)
zone := time.FixedZone("CST", 8*3600)
return basic.JDE2DateByZone(jde, zone, true)
}
// GanZhi 返回传入年份对应的干支
func GanZhi(year int) string {
return basic.GetGZ(year)
}
// JieQi 返回传入年份、节气对应的北京时间节气时间
func JieQi(year, term int) time.Time {
calcJde := basic.GetJQTime(year, term)
zone := time.FixedZone("CST", 8*3600)
return basic.JDE2DateByZone(calcJde, zone, false)
}
// WuHou 返回传入年份、物候对应的北京时间物候时间
func WuHou(year, term int) time.Time {
calcJde := basic.GetWHTime(year, term)
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 !useGoto && 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
if uint8(magic&0x3FFE>>(13-i))&1 == 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
if uint8(magic&0x3FFE>>(13-i))&1 == 1 {
dayofLunar++
}
totalDay += dayofLunar
lunarMonth++
if lunarMonth-leapMonth == 1 && !leap {
leap = true
lunarMonth--
} else {
leap = false
}
}
return time.Time{}
}