220 lines
5.5 KiB
Go
220 lines
5.5 KiB
Go
|
|
package basic
|
||
|
|
|
||
|
|
import "math"
|
||
|
|
|
||
|
|
func GetLunar(year, month, day int, tz float64) (lyear, lmonth, lday int, leap bool, result string) {
|
||
|
|
julianDayEpoch := JDECalc(year, month, float64(day))
|
||
|
|
// 确定农历年份
|
||
|
|
lyear = year
|
||
|
|
adjustedYear := year
|
||
|
|
if month == 11 || month == 12 {
|
||
|
|
winterSolsticeDay := GetJQTime(year, 270) + tz
|
||
|
|
//firstNewMoonDay := TD2UT(CalcMoonS(float64(year)+11.0/12.0+5.0/30.0/12.0, 0), true) + tz
|
||
|
|
//nextNewMoonDay := TD2UT(CalcMoonS(float64(year)+1.0, 0), true) + tz
|
||
|
|
firstNewMoonDay := TD2UT(CalcMoonSHByJDE(winterSolsticeDay-16, 0), false) + tz
|
||
|
|
nextNewMoonDay := TD2UT(CalcMoonSHByJDE(firstNewMoonDay+28, 0), false) + tz
|
||
|
|
|
||
|
|
firstNewMoonDay = normalizeTimePoint(firstNewMoonDay)
|
||
|
|
nextNewMoonDay = normalizeTimePoint(nextNewMoonDay)
|
||
|
|
|
||
|
|
if winterSolsticeDay >= firstNewMoonDay && winterSolsticeDay < nextNewMoonDay && julianDayEpoch < firstNewMoonDay {
|
||
|
|
adjustedYear--
|
||
|
|
}
|
||
|
|
if winterSolsticeDay >= nextNewMoonDay && julianDayEpoch < nextNewMoonDay {
|
||
|
|
adjustedYear--
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
adjustedYear--
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取节气和朔望月数据
|
||
|
|
solarTerms := GetJieqiLoops(adjustedYear, 25)
|
||
|
|
newMoonDays := GetMoonLoops(float64(adjustedYear), 17)
|
||
|
|
|
||
|
|
// 计算冬至日期
|
||
|
|
winterSolsticeFirst := normalizeTimePoint(solarTerms[0] - 8.0/24 + tz)
|
||
|
|
winterSolsticeSecond := normalizeTimePoint(solarTerms[24] - 8.0/24 + tz)
|
||
|
|
|
||
|
|
// 规范化时间点
|
||
|
|
normalizeTimeArray(newMoonDays, tz)
|
||
|
|
normalizeTimeArray(solarTerms, tz)
|
||
|
|
|
||
|
|
// 计算朔望月范围
|
||
|
|
minMoonIndex, maxMoonIndex := 20, 0
|
||
|
|
moonCount := 0
|
||
|
|
for i := 0; i < len(newMoonDays)-1; i++ {
|
||
|
|
if (newMoonDays[i] <= winterSolsticeFirst && newMoonDays[i+1] > winterSolsticeFirst) ||
|
||
|
|
(newMoonDays[i] > winterSolsticeFirst && newMoonDays[i] < winterSolsticeSecond && newMoonDays[i+1] <= winterSolsticeSecond) {
|
||
|
|
if i <= minMoonIndex {
|
||
|
|
minMoonIndex = i
|
||
|
|
}
|
||
|
|
if i >= maxMoonIndex {
|
||
|
|
maxMoonIndex = i
|
||
|
|
}
|
||
|
|
moonCount++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 确定闰月位置
|
||
|
|
leapMonthPos := 20
|
||
|
|
if moonCount >= 13 {
|
||
|
|
solarTermIndex, i := 0, 0
|
||
|
|
for i = minMoonIndex; i <= maxMoonIndex; i++ {
|
||
|
|
if !(newMoonDays[i] <= solarTerms[solarTermIndex] && newMoonDays[i+1] > solarTerms[solarTermIndex]) {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
solarTermIndex += 2
|
||
|
|
}
|
||
|
|
leapMonthPos = i - minMoonIndex
|
||
|
|
}
|
||
|
|
|
||
|
|
// 找到当前月相索引
|
||
|
|
currentMoonIndex := 0
|
||
|
|
for currentMoonIndex = minMoonIndex; currentMoonIndex <= maxMoonIndex; currentMoonIndex++ {
|
||
|
|
if newMoonDays[currentMoonIndex] > julianDayEpoch {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 计算农历月份
|
||
|
|
lmonth = currentMoonIndex - minMoonIndex - 1
|
||
|
|
shouldAdjustLeap := false
|
||
|
|
leap = false
|
||
|
|
|
||
|
|
if lmonth >= leapMonthPos {
|
||
|
|
shouldAdjustLeap = true
|
||
|
|
}
|
||
|
|
if lmonth == leapMonthPos {
|
||
|
|
leap = true
|
||
|
|
}
|
||
|
|
if lmonth < 2 {
|
||
|
|
lmonth += 11
|
||
|
|
} else {
|
||
|
|
lmonth--
|
||
|
|
}
|
||
|
|
if shouldAdjustLeap {
|
||
|
|
lmonth--
|
||
|
|
}
|
||
|
|
if lmonth <= 0 {
|
||
|
|
lmonth += 12
|
||
|
|
}
|
||
|
|
|
||
|
|
// 计算农历日期
|
||
|
|
lday = int(julianDayEpoch-newMoonDays[currentMoonIndex-1]) + 1
|
||
|
|
|
||
|
|
// 生成农历日期字符串
|
||
|
|
result = formatLunarDateString(lmonth, lday, leap)
|
||
|
|
if lmonth >= 10 && month < 3 {
|
||
|
|
lyear--
|
||
|
|
}
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
func GetSolar(year, month, day int, leap bool, tz float64) float64 {
|
||
|
|
adjustedYear := year
|
||
|
|
if month < 11 {
|
||
|
|
adjustedYear--
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取节气和朔望月数据
|
||
|
|
solarTerms := GetJieqiLoops(adjustedYear, 25)
|
||
|
|
newMoonDays := GetMoonLoops(float64(adjustedYear), 17)
|
||
|
|
|
||
|
|
// 计算冬至日期
|
||
|
|
winterSolsticeFirst := normalizeTimePoint(solarTerms[0] - 8.0/24 + tz)
|
||
|
|
winterSolsticeSecond := normalizeTimePoint(solarTerms[24] - 8.0/24 + tz)
|
||
|
|
|
||
|
|
// 规范化时间点
|
||
|
|
normalizeTimeArray(newMoonDays, tz)
|
||
|
|
normalizeTimeArray(solarTerms, tz)
|
||
|
|
|
||
|
|
// 计算朔望月范围
|
||
|
|
minMoonIndex, maxMoonIndex := 20, 0
|
||
|
|
moonCount := 0
|
||
|
|
for i := 0; i < 15; i++ {
|
||
|
|
if (newMoonDays[i] <= winterSolsticeFirst && newMoonDays[i+1] > winterSolsticeFirst) ||
|
||
|
|
(newMoonDays[i] > winterSolsticeFirst && newMoonDays[i] < winterSolsticeSecond && newMoonDays[i+1] <= winterSolsticeSecond) {
|
||
|
|
if i <= minMoonIndex {
|
||
|
|
minMoonIndex = i
|
||
|
|
}
|
||
|
|
if i >= maxMoonIndex {
|
||
|
|
maxMoonIndex = i
|
||
|
|
}
|
||
|
|
moonCount++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 确定闰月位置
|
||
|
|
leapMonthPos := 20
|
||
|
|
if moonCount >= 13 {
|
||
|
|
solarTermIndex, i := 0, 0
|
||
|
|
for i = minMoonIndex; i <= maxMoonIndex; i++ {
|
||
|
|
if !(newMoonDays[i] <= solarTerms[solarTermIndex] && newMoonDays[i+1] > solarTerms[solarTermIndex]) {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
solarTermIndex += 2
|
||
|
|
}
|
||
|
|
leapMonthPos = i - minMoonIndex
|
||
|
|
}
|
||
|
|
actualMonth := month
|
||
|
|
if actualMonth > 10 {
|
||
|
|
actualMonth -= 11
|
||
|
|
} else {
|
||
|
|
actualMonth++
|
||
|
|
}
|
||
|
|
// 计算实际月份索引
|
||
|
|
if leap {
|
||
|
|
actualMonth++
|
||
|
|
}
|
||
|
|
|
||
|
|
if actualMonth >= leapMonthPos && !leap {
|
||
|
|
actualMonth++
|
||
|
|
}
|
||
|
|
|
||
|
|
return newMoonDays[minMoonIndex+actualMonth] + float64(day) - 1
|
||
|
|
}
|
||
|
|
|
||
|
|
func normalizeTimeArray(timeArray []float64, tz float64) {
|
||
|
|
for idx, timeValue := range timeArray {
|
||
|
|
adjustedTime := timeValue
|
||
|
|
if tz != 8.0/24 {
|
||
|
|
adjustedTime = timeValue - 8.0/24 + tz
|
||
|
|
}
|
||
|
|
timeArray[idx] = normalizeTimePoint(adjustedTime)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func normalizeTimePoint(timePoint float64) float64 {
|
||
|
|
if timePoint-math.Floor(timePoint) > 0.5 {
|
||
|
|
return math.Floor(timePoint) + 0.5
|
||
|
|
}
|
||
|
|
return math.Floor(timePoint) - 0.5
|
||
|
|
}
|
||
|
|
|
||
|
|
func formatLunarDateString(lunarMonth, lunarDay int, isLeap bool) string {
|
||
|
|
monthNames := []string{"十", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊"}
|
||
|
|
dayPrefixes := []string{"初", "十", "廿", "三"}
|
||
|
|
|
||
|
|
var dateString string
|
||
|
|
|
||
|
|
if isLeap {
|
||
|
|
dateString += "闰"
|
||
|
|
}
|
||
|
|
|
||
|
|
if lunarMonth == 1 {
|
||
|
|
dateString += "正月"
|
||
|
|
} else {
|
||
|
|
dateString += monthNames[lunarMonth] + "月"
|
||
|
|
}
|
||
|
|
|
||
|
|
if lunarDay == 20 {
|
||
|
|
dateString += "二十"
|
||
|
|
} else if lunarDay == 10 {
|
||
|
|
dateString += "初十"
|
||
|
|
} else {
|
||
|
|
dateString += dayPrefixes[lunarDay/10] + monthNames[lunarDay%10]
|
||
|
|
}
|
||
|
|
|
||
|
|
return dateString
|
||
|
|
}
|