package calendar import ( "fmt" "math" "time" "b612.me/astro/basic" ) const ( hanQingJieQiMinYear = -104 hanQingJieQiMaxYear = 1912 hanQingJieQiPatternCount = 97 hanQingJieQiPatternLength = 23 ) func hanQingCalendricalJieQiDate(year, term int) (time.Time, error) { termIndex, err := calendricalJieQiTableTermIndex(term) if err != nil { return time.Time{}, err } if year < hanQingJieQiMinYear || year > hanQingJieQiMaxYear { return time.Time{}, fmt.Errorf("该年份暂不支持历法节气") } return hanQingCalendricalJieQiDateInRow(year, termIndex) } func hanQingCalendricalJieQiDateInRow(rowYear, termIndex int) (time.Time, error) { yearIndex := rowYear - hanQingJieQiMinYear offset := packedBits(hanQingJieQiFirstPacked, yearIndex*4, 4) - 4 patternID := packedBits(hanQingJieQiPatternIndexPacked, yearIndex*7, 7) if patternID >= hanQingJieQiPatternCount { return time.Time{}, fmt.Errorf("历法节气表数据异常") } for i := 0; i < termIndex; i++ { offset += hanQingJieQiPatternDelta(patternID, i) } baseJDN := int(math.Floor(basic.JDECalc(rowYear-1, 12, 31) + 0.5)) return basic.JDE2DateByZone(float64(baseJDN+offset)-0.5, getCst(), true), nil } func calendricalJieQiTableTermIndex(term int) (int, error) { if term < 0 || term >= 360 || term%15 != 0 { return 0, fmt.Errorf("节气参数超出范围") } return ((term - JQ_小寒 + 360) % 360) / 15, nil } func hanQingJieQiPatternDelta(patternID, pos int) int { key := patternID*hanQingJieQiPatternLength + pos if delta, ok := hanQingJieQiPatternExceptionDelta(key); ok { return delta } if packedBits(hanQingJieQiPatternBits, key, 1) == 1 { return 16 } return 15 } func hanQingJieQiPatternExceptionDelta(key int) (int, bool) { for _, item := range hanQingJieQiPatternExceptions { if int(item&0x0FFF) != key { continue } switch item >> 12 { case 0: return 12, true case 1: return 14, true case 2: return 17, true } return 15, true } return 0, false } func packedBits(data []byte, offset, width int) int { value := 0 for i := 0; i < width; i++ { bit := offset + i if data[bit/8]&(1<