2025-09-15 20:55:38 +08:00
package calendar
import (
"time"
2026-05-01 22:38:44 +08:00
"b612.me/astro/basic"
2025-09-15 20:55:38 +08:00
)
type LunarInfo struct {
// SolarDate 公历日期
SolarDate time . Time ` json:"solarDate" `
// LunarYear 农历年的公历映射, 如2025
LunarYear int ` json:"lunarYear" `
// LunarYearChn 农历年公历映射中文表示,比如二零二五
LunarYearChn string ` json:"lunarYearChn" `
// LunarMonth 农历月, 表示以当时的历法推定的农历月与正月的距离, 正月为1, 二月为2, 依次类推
// 武则天改历时期, 正月为1, 十二月为2,一月为3, 二月为4,以此类推
LunarMonth int ` json:"lunarMonth" `
// LunarDay 农历日,[1-30]
LunarDay int ` json:"lunarDay" `
// IsLeap 是否闰月
IsLeap bool ` json:"isLeap" `
// LunarMonthDayDesc 农历月日描述,如正月初一。此处,十一月表示为冬月,十二月表示为腊月
LunarMonthDayDesc string ` json:"lunarMonthDayDesc" `
// GanzhiYear 农历年干支
GanzhiYear string ` json:"ganzhiYear" `
// GanzhiMonth 农历月干支,闰月从上一个月
GanzhiMonth string ` json:"ganzhiMonth" `
// GanzhiDay 农历日干支
GanzhiDay string ` json:"ganzhiDay" `
// Dynasty 朝代,如唐、宋、元、明、清等
Dynasty string ` json:"dynasty" `
// Emperor 皇帝姓名(仅供参考,多个皇帝用同一个年号的场景,此处不准)
Emperor string ` json:"emperor" `
// Nianhao 年号 如"开元"
Nianhao string ` json:"nianhao" `
// YearOfNianhao 该年号的第几年
YearOfNianhao int ` json:"yearOfNianhao" `
// EraDesc 年代描述,如唐玄宗开元二年
EraDesc string ` json:"eraDesc" `
// LunarWithEraDesc 农历日期加上年代描述,如开元二年正月初一
LunarWithEraDesc string ` json:"lunarWithNianhaoDesc" `
// ChineseZodiac 生肖
ChineseZodiac string ` json:"chineseZodiac" `
}
type Time struct {
solarTime time . Time
lunars [ ] LunarTime
}
2026-05-01 22:38:44 +08:00
// Solar 公历时间 / solar time.
//
// 返回内部保存的公历 `time.Time`,不做时区或历法再计算。
2026-05-27 16:08:11 +08:00
// Returns the stored civil `time.Time` directly, without any further time-zone or calendar conversion.
2025-09-15 20:55:38 +08:00
func ( t Time ) Solar ( ) time . Time {
return t . solarTime
}
2026-05-01 22:38:44 +08:00
// Time 公历时间 / solar time.
//
// 是 `Solar` 的同义接口,便于把 `calendar.Time` 当作普通时间对象使用。
2026-05-27 16:08:11 +08:00
// This is an alias of `Solar`, convenient when `calendar.Time` is used as a regular time object.
2025-09-15 20:55:38 +08:00
func ( t Time ) Time ( ) time . Time {
return t . solarTime
}
2026-05-01 22:38:44 +08:00
// Lunars 农历候选结果 / lunar candidates.
//
// 返回全部候选农历结果。
2026-05-27 16:08:11 +08:00
// Returns all candidate lunar-calendar results.
2025-09-15 20:55:38 +08:00
func ( t Time ) Lunars ( ) [ ] LunarTime {
return t . lunars
}
2026-05-01 22:38:44 +08:00
// LunarDesc 农历描述 / lunar descriptions.
//
// 返回全部候选结果的农历描述,如开元二年正月初一;若无年号,则返回年份描述,如二零二五年正月初一。
2026-05-27 16:08:11 +08:00
// Returns the lunar-date descriptions for all candidates. If no era name is available, the year is described directly.
2025-09-15 20:55:38 +08:00
func ( t Time ) LunarDesc ( ) [ ] string {
var res [ ] string
for _ , v := range t . lunars {
res = append ( res , v . LunarDesc ( ) ... )
}
return res
}
2026-05-01 22:38:44 +08:00
// LunarDescWithEmperor 含君主信息的农历描述 / lunar descriptions with emperor.
//
// 返回全部候选结果中含有君主信息的农历描述,如唐玄宗 开元二年正月初一;若无年号,则返回年份描述,如二零二五年正月初一。
2026-05-27 16:08:11 +08:00
// Returns the candidate descriptions with emperor names when available. If no era name is available, the year is described directly.
2025-09-15 20:55:38 +08:00
func ( t Time ) LunarDescWithEmperor ( ) [ ] string {
var res [ ] string
for _ , v := range t . lunars {
res = append ( res , v . LunarDescWithEmperor ( ) ... )
}
return res
}
2026-05-01 22:38:44 +08:00
// LunarDescWithDynasty 含朝代信息的农历描述 / lunar descriptions with dynasty.
//
// 返回全部候选结果中含有朝代信息的农历描述,如唐 开元二年正月初一;若无年号,则返回年份描述,如二零二五年正月初一。
2026-05-27 16:08:11 +08:00
// Returns the candidate descriptions with dynasty names when available. If no era name is available, the year is described directly.
2025-09-15 20:55:38 +08:00
func ( t Time ) LunarDescWithDynasty ( ) [ ] string {
var res [ ] string
for _ , v := range t . lunars {
res = append ( res , v . LunarDescWithDynasty ( ) ... )
}
return res
}
2026-05-01 22:38:44 +08:00
// LunarDescWithDynastyAndEmperor 含朝代与君主信息的农历描述 / lunar descriptions with dynasty and emperor.
//
// 返回全部候选结果中含有朝代和君主信息的农历描述,如唐 唐玄宗 开元二年正月初一;若无年号,则返回年份描述,如二零二五年正月初一。
2026-05-27 16:08:11 +08:00
// Returns the candidate descriptions with both dynasty and emperor names when available. If no era name is available, the year is described directly.
2025-09-15 20:55:38 +08:00
func ( t Time ) LunarDescWithDynastyAndEmperor ( ) [ ] string {
var res [ ] string
for _ , v := range t . lunars {
res = append ( res , v . LunarDescWithDynastyAndEmperor ( ) ... )
}
return res
}
2026-05-01 22:38:44 +08:00
// LunarInfo 农历结构化信息 / structured lunar information.
//
// 返回全部候选结果对应的结构化农历信息切片。
2026-05-27 16:08:11 +08:00
// Returns the structured lunar-calendar information for all candidates.
2025-09-15 20:55:38 +08:00
func ( t Time ) LunarInfo ( ) [ ] LunarInfo {
var res [ ] LunarInfo
for _ , v := range t . lunars {
res = append ( res , v . LunarInfo ( ) ... )
}
return res
}
2026-05-01 22:38:44 +08:00
// Eras 朝代、皇帝、年号信息 / era information.
//
// 返回全部候选结果对应的朝代、皇帝、年号信息。
2026-05-27 16:08:11 +08:00
// Returns the dynasty, emperor, and era-name records associated with all candidates.
2025-09-15 20:55:38 +08:00
func ( t Time ) Eras ( ) [ ] EraDesc {
var res [ ] EraDesc
for _ , v := range t . lunars {
res = append ( res , v . eras ... )
}
return res
}
2026-05-01 22:38:44 +08:00
// Lunar 首个农历结果 / first lunar result.
//
// 若存在多个候选结果,只返回第一个;无结果时返回零值 `LunarTime`。
2026-05-27 16:08:11 +08:00
// Returns only the first candidate when multiple results exist. A zero-value `LunarTime` is returned when no result is available.
2025-09-15 20:55:38 +08:00
func ( t Time ) Lunar ( ) LunarTime {
if len ( t . lunars ) > 0 {
return t . lunars [ 0 ]
}
return LunarTime { }
}
2026-05-01 22:38:44 +08:00
// Add 时间偏移 / add a duration.
//
// 返回公历时间偏移后的农历结果。
2026-05-27 16:08:11 +08:00
// Returns the lunar-calendar result after applying the duration to the stored civil time.
2025-09-15 20:55:38 +08:00
func ( t Time ) Add ( d time . Duration ) Time {
if d < time . Second {
newT := t . solarTime . Add ( d )
rT , _ := SolarToLunar ( newT )
return rT
}
sec := d . Seconds ( )
jde := Date2JDE ( t . solarTime )
jde += sec / 86400.0
2026-05-01 22:38:44 +08:00
newT := basic . JDE2DateByZone ( jde , t . solarTime . Location ( ) , true )
2025-09-15 20:55:38 +08:00
rT , _ := SolarToLunar ( newT )
return rT
}
type LunarTime struct {
solarDate time . Time
//农历年
year int
//农历月, 表示以当时的历法推定的农历月与正月的距离, 正月为1, 二月为2, 依次类推, 闰月显示所闰月
month int
//农历日
day int
//是否闰月
leap bool
//农历描述
desc string
//备注
comment string
//ganzhi of month 月干支
ganzhiMonth string
eras [ ] EraDesc
}
2026-05-01 22:38:44 +08:00
// ShengXiao 生肖 / Chinese zodiac.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) ShengXiao ( ) string {
shengxiao := [ ] string { "猴" , "鸡" , "狗" , "猪" , "鼠" , "牛" , "虎" , "兔" , "龙" , "蛇" , "马" , "羊" }
diff := l . LunarYear ( ) % 12
if diff < 0 {
diff += 12
}
return shengxiao [ diff ]
}
2026-05-01 22:38:44 +08:00
// Zodiac 生肖别名 / zodiac alias.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) Zodiac ( ) string {
return l . ShengXiao ( )
}
2026-05-01 22:38:44 +08:00
// GanZhiYear 年干支 / sexagenary year name.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) GanZhiYear ( ) string {
return GanZhiOfYear ( l . year )
}
2026-05-01 22:38:44 +08:00
// GanZhiMonth 月干支 / sexagenary month name.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) GanZhiMonth ( ) string {
return l . ganzhiMonth
}
2026-05-01 22:38:44 +08:00
// GanZhiDay 日干支 / sexagenary day name.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) GanZhiDay ( ) string {
return GanZhiOfDay ( l . solarDate )
}
2026-05-01 22:38:44 +08:00
// LunarYear 农历年 / lunar year.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) LunarYear ( ) int {
return l . year
}
2026-05-01 22:38:44 +08:00
// LunarMonth 农历月 / lunar month.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) LunarMonth ( ) int {
return l . month
}
2026-05-01 22:38:44 +08:00
// LunarDay 农历日 / lunar day.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) LunarDay ( ) int {
return l . day
}
2026-05-01 22:38:44 +08:00
// IsLeap 是否闰月 / whether the month is leap.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) IsLeap ( ) bool {
return l . leap
}
2026-05-01 22:38:44 +08:00
// Eras 朝代、皇帝、年号信息 / era information.
//
// 返回该农历结果对应的朝代、皇帝、年号信息。
2026-05-27 16:08:11 +08:00
// Returns the dynasty, emperor, and era-name records associated with this lunar result.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) Eras ( ) [ ] EraDesc {
return l . eras
}
2026-05-01 22:38:44 +08:00
// MonthDay 农历月日描述 / lunar month-day description.
//
// 获取农历月日描述,如正月初一。此处,十一月表示为冬月,十二月表示为腊月。
2026-05-27 16:08:11 +08:00
// Returns the lunar month-day description, such as `正月初一`. In this package, month 11 is written as `冬月` and month 12 as `腊月`.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) MonthDay ( ) string {
return l . desc
}
2026-05-01 22:38:44 +08:00
// LunarDesc 农历描述 / lunar descriptions.
//
// 获取农历描述,如开元二年正月初一,若无年号,则返回年份描述,如二零二五年正月初一。
2026-05-27 16:08:11 +08:00
// Returns the lunar-date descriptions for this result. If no era name is available, the year is described directly.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) LunarDesc ( ) [ ] string {
return l . innerDescWithNianHao ( false , false )
}
2026-05-01 22:38:44 +08:00
// LunarDescWithEmperor 含君主信息的农历描述 / lunar descriptions with emperor.
//
// 获取含有君主信息的农历描述,如唐玄宗 开元二年正月初一,若无年号,则返回年份描述,如二零二五年正月初一。
2025-09-15 20:55:38 +08:00
// 君主信息仅供参考,多个皇帝用同一个年号的场景,此处不准
2026-05-27 16:08:11 +08:00
// Returns the lunar-date descriptions with emperor names when available. Emperor names are for reference only and may be ambiguous when multiple emperors used the same era name.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) LunarDescWithEmperor ( ) [ ] string {
return l . innerDescWithNianHao ( true , false )
}
2026-05-01 22:38:44 +08:00
// LunarDescWithDynasty 含朝代信息的农历描述 / lunar descriptions with dynasty.
//
// 获取含有朝代信息的农历描述,如唐 开元二年正月初一,若无年号,则返回年份描述,如二零二五年正月初一。
2026-05-27 16:08:11 +08:00
// Returns the lunar-date descriptions with dynasty names when available. If no era name is available, the year is described directly.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) LunarDescWithDynasty ( ) [ ] string {
return l . innerDescWithNianHao ( false , true )
}
2026-05-01 22:38:44 +08:00
// LunarDescWithDynastyAndEmperor 含朝代和君主信息的农历描述 / lunar descriptions with dynasty and emperor.
//
// 获取含有朝代和君主信息的农历描述,如唐 唐玄宗 开元二年正月初一,若无年号,则返回年份描述,如二零二五年正月初一。
2025-09-15 20:55:38 +08:00
// 君主信息仅供参考,多个皇帝用同一个年号的场景,此处不准
2026-05-27 16:08:11 +08:00
// Returns the lunar-date descriptions with both dynasty and emperor names when available. Emperor names are for reference only and may be ambiguous when multiple emperors used the same era name.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) LunarDescWithDynastyAndEmperor ( ) [ ] string {
return l . innerDescWithNianHao ( true , true )
}
func ( l LunarTime ) innerDescWithNianHao ( withEmperor bool , withDynasty bool ) [ ] string {
var res [ ] string
if len ( l . eras ) > 0 {
for _ , v := range l . eras {
tmp := v . String ( ) + l . desc
if withEmperor {
tmp = v . Emperor + " " + tmp
}
if withDynasty {
tmp = v . Dynasty + " " + tmp
}
res = append ( res , tmp )
}
} else {
res = append ( res , number2Chinese ( l . year , true ) + "年" + l . desc )
}
return res
}
2026-05-01 22:38:44 +08:00
// LunarInfo 农历结构化信息 / structured lunar information.
//
// 返回该农历结果对应的结构化农历信息切片;若存在多个并行年号,则会有多条记录。
2026-05-27 16:08:11 +08:00
// Returns the structured lunar-calendar information for this result. Multiple records are returned when parallel era-name interpretations exist.
2025-09-15 20:55:38 +08:00
func ( l LunarTime ) LunarInfo ( ) [ ] LunarInfo {
var res [ ] LunarInfo
for _ , v := range l . eras {
li := LunarInfo {
SolarDate : l . solarDate ,
LunarYear : l . year ,
LunarYearChn : number2Chinese ( l . year , true ) ,
LunarMonth : l . month ,
LunarDay : l . day ,
IsLeap : l . leap ,
LunarMonthDayDesc : l . desc ,
GanzhiYear : GanZhiOfYear ( l . year ) ,
GanzhiMonth : l . ganzhiMonth ,
GanzhiDay : GanZhiOfDay ( l . solarDate ) ,
Dynasty : v . Dynasty ,
Emperor : v . Emperor ,
Nianhao : v . Nianhao ,
YearOfNianhao : v . YearOfNianHao ,
EraDesc : v . String ( ) ,
LunarWithEraDesc : v . String ( ) + l . desc ,
ChineseZodiac : l . ShengXiao ( ) ,
}
res = append ( res , li )
}
if len ( l . eras ) == 0 {
li := LunarInfo {
SolarDate : l . solarDate ,
LunarYear : l . year ,
LunarYearChn : number2Chinese ( l . year , true ) ,
LunarMonth : l . month ,
LunarDay : l . day ,
IsLeap : l . leap ,
LunarMonthDayDesc : l . desc ,
GanzhiYear : GanZhiOfYear ( l . year ) ,
GanzhiMonth : l . ganzhiMonth ,
GanzhiDay : GanZhiOfDay ( l . solarDate ) ,
Dynasty : "" ,
Emperor : "" ,
Nianhao : "" ,
YearOfNianhao : 0 ,
EraDesc : number2Chinese ( l . year , true ) + "年" ,
LunarWithEraDesc : number2Chinese ( l . year , true ) + "年" + l . desc ,
ChineseZodiac : l . ShengXiao ( ) ,
}
res = append ( res , li )
}
return res
}