calendar: 补齐前104古历纪年解析与回归测试
- 为先秦与秦汉古历结果填充周、鲁、秦、西汉早期纪年信息 - 支持默认与显式古历下的年号日期解析
This commit is contained in:
parent
a8e7513683
commit
25dc7ac0bc
@ -518,6 +518,21 @@ func parseChineseDate(dateStr string) (LunarTime, error) {
|
|||||||
var result LunarTime
|
var result LunarTime
|
||||||
var err error
|
var err error
|
||||||
result.desc = dateStr
|
result.desc = dateStr
|
||||||
|
if strings.HasPrefix(dateStr, "前") {
|
||||||
|
originDateStr := dateStr
|
||||||
|
dateStr = strings.TrimPrefix(dateStr, "前")
|
||||||
|
re := regexp.MustCompile(`^([-一二三四五六七八九十零〇\d]+?)年`)
|
||||||
|
matches := re.FindStringSubmatch(dateStr)
|
||||||
|
if len(matches) == 2 {
|
||||||
|
year, err := parseDirectYear(matches[1])
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
dateStr = "-" + strconv.Itoa(year-1) + strings.TrimPrefix(dateStr, matches[1])
|
||||||
|
} else {
|
||||||
|
dateStr = originDateStr
|
||||||
|
}
|
||||||
|
}
|
||||||
dateStr = "公元" + dateStr
|
dateStr = "公元" + dateStr
|
||||||
// 正则表达式匹配日期格式
|
// 正则表达式匹配日期格式
|
||||||
re := regexp.MustCompile(`^([\p{Han}]+?)([-负負一二三四五六七八九十零〇\d]*?元?)年([\p{Han}\d]+?)月([\p{Han}\d]+?)日?$`)
|
re := regexp.MustCompile(`^([\p{Han}]+?)([-负負一二三四五六七八九十零〇\d]*?元?)年([\p{Han}\d]+?)月([\p{Han}\d]+?)日?$`)
|
||||||
@ -614,6 +629,21 @@ func parseChineseDate(dateStr string) (LunarTime, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseDirectYear(yearStr string) (int, error) {
|
||||||
|
if m, _ := regexp.MatchString("\\d+", yearStr); m {
|
||||||
|
year, err := strconv.Atoi(yearStr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("无效的年份: %s", yearStr)
|
||||||
|
}
|
||||||
|
return year, nil
|
||||||
|
}
|
||||||
|
year := transfer(yearStr, true)
|
||||||
|
if year == 0 {
|
||||||
|
return 0, fmt.Errorf("无效的年份: %s", yearStr)
|
||||||
|
}
|
||||||
|
return year, nil
|
||||||
|
}
|
||||||
|
|
||||||
// convertChineseNumber 将中文数字转换为阿拉伯数字
|
// convertChineseNumber 将中文数字转换为阿拉伯数字
|
||||||
func convertChineseNumber(chineseNum string) (int, error) {
|
func convertChineseNumber(chineseNum string) (int, error) {
|
||||||
if num, ok := chineseNumbers[chineseNum]; ok {
|
if num, ok := chineseNumbers[chineseNum]; ok {
|
||||||
|
|||||||
@ -101,6 +101,11 @@ func LunarToSolarWithCalendar(desc string, system AncientCalendarSystem) ([]Time
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if date.year == 0 || date.comment != "" {
|
if date.year == 0 || date.comment != "" {
|
||||||
|
if date.comment != "" {
|
||||||
|
if result, known, err := lunarToSolarAncientEra(date, system); known {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("显式古历暂不支持年号日期")
|
return nil, fmt.Errorf("显式古历暂不支持年号日期")
|
||||||
}
|
}
|
||||||
if date.houMonth && system != AncientCalendarQinHan && system != AncientCalendarZhuanxu {
|
if date.houMonth && system != AncientCalendarQinHan && system != AncientCalendarZhuanxu {
|
||||||
@ -616,6 +621,7 @@ func ancientTime(date time.Time, month ancientMonth) Time {
|
|||||||
desc: formatAncientLunarDateString(month.month, month.day, month.leap, month.system),
|
desc: formatAncientLunarDateString(month.month, month.day, month.leap, month.system),
|
||||||
calendarSystem: month.system,
|
calendarSystem: month.system,
|
||||||
calendarName: month.name,
|
calendarName: month.name,
|
||||||
|
eras: ancientErasForLunarYear(month.lunarYear, month.system),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -625,6 +631,9 @@ func tagCalendar(date Time, system AncientCalendarSystem, name string) Time {
|
|||||||
for i := range date.lunars {
|
for i := range date.lunars {
|
||||||
date.lunars[i].calendarSystem = system
|
date.lunars[i].calendarSystem = system
|
||||||
date.lunars[i].calendarName = name
|
date.lunars[i].calendarName = name
|
||||||
|
if len(date.lunars[i].eras) == 0 {
|
||||||
|
date.lunars[i].eras = ancientErasForLunarYear(date.lunars[i].year, system)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return date
|
return date
|
||||||
}
|
}
|
||||||
|
|||||||
212
calendar/chineseAncientEra.go
Normal file
212
calendar/chineseAncientEra.go
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
package calendar
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type ancientEraSource struct {
|
||||||
|
system AncientCalendarSystem
|
||||||
|
min int
|
||||||
|
max int
|
||||||
|
eras []Era
|
||||||
|
}
|
||||||
|
|
||||||
|
var zhouAncientEras = []Era{
|
||||||
|
{Year: -313, Emperor: "周赧王", Nianhao: "周赧王", Dynasty: "周"},
|
||||||
|
{Year: -319, Emperor: "周慎靓王", Nianhao: "周慎靓王", Dynasty: "周"},
|
||||||
|
{Year: -367, Emperor: "周显王", Nianhao: "周显王", Dynasty: "周"},
|
||||||
|
{Year: -374, Emperor: "周烈王", Nianhao: "周烈王", Dynasty: "周"},
|
||||||
|
{Year: -400, Emperor: "周安王", Nianhao: "周安王", Dynasty: "周"},
|
||||||
|
{Year: -424, Emperor: "周威烈王", Nianhao: "周威烈王", Dynasty: "周"},
|
||||||
|
{Year: -439, Emperor: "周考王", Nianhao: "周考王", Dynasty: "周"},
|
||||||
|
{Year: -467, Emperor: "周贞定王", Nianhao: "周贞定王", Dynasty: "周"},
|
||||||
|
{Year: -475, Emperor: "周元王", Nianhao: "周元王", Dynasty: "周"},
|
||||||
|
{Year: -518, Emperor: "周敬王", Nianhao: "周敬王", Dynasty: "周"},
|
||||||
|
{Year: -543, Emperor: "周景王", Nianhao: "周景王", Dynasty: "周"},
|
||||||
|
{Year: -570, Emperor: "周灵王", Nianhao: "周灵王", Dynasty: "周"},
|
||||||
|
{Year: -584, Emperor: "周简王", Nianhao: "周简王", Dynasty: "周"},
|
||||||
|
{Year: -605, Emperor: "周定王", Nianhao: "周定王", Dynasty: "周"},
|
||||||
|
{Year: -611, Emperor: "周匡王", Nianhao: "周匡王", Dynasty: "周"},
|
||||||
|
{Year: -617, Emperor: "周顷王", Nianhao: "周顷王", Dynasty: "周"},
|
||||||
|
{Year: -650, Emperor: "周襄王", Nianhao: "周襄王", Dynasty: "周"},
|
||||||
|
{Year: -675, Emperor: "周惠王", Nianhao: "周惠王", Dynasty: "周"},
|
||||||
|
{Year: -680, Emperor: "周僖王", Nianhao: "周僖王", Dynasty: "周"},
|
||||||
|
{Year: -695, Emperor: "周庄王", Nianhao: "周庄王", Dynasty: "周"},
|
||||||
|
{Year: -718, Emperor: "周桓王", Nianhao: "周桓王", Dynasty: "周"},
|
||||||
|
{Year: -771, Emperor: "周平王", Nianhao: "周平王", Dynasty: "周"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var luAncientEras = []Era{
|
||||||
|
{Year: -271, Emperor: "鲁顷公", Nianhao: "鲁顷公", Dynasty: "鲁"},
|
||||||
|
{Year: -294, Emperor: "鲁文公", Nianhao: "鲁文公", Dynasty: "鲁"},
|
||||||
|
{Year: -313, Emperor: "鲁平公", Nianhao: "鲁平公", Dynasty: "鲁"},
|
||||||
|
{Year: -342, Emperor: "鲁景公", Nianhao: "鲁景公", Dynasty: "鲁"},
|
||||||
|
{Year: -351, Emperor: "鲁康公", Nianhao: "鲁康公", Dynasty: "鲁"},
|
||||||
|
{Year: -375, Emperor: "鲁共公", Nianhao: "鲁共公", Dynasty: "鲁"},
|
||||||
|
{Year: -406, Emperor: "鲁穆公", Nianhao: "鲁穆公", Dynasty: "鲁"},
|
||||||
|
{Year: -427, Emperor: "鲁元公", Nianhao: "鲁元公", Dynasty: "鲁"},
|
||||||
|
{Year: -465, Emperor: "鲁悼公", Nianhao: "鲁悼公", Dynasty: "鲁"},
|
||||||
|
{Year: -493, Emperor: "鲁哀公", Nianhao: "鲁哀公", Dynasty: "鲁"},
|
||||||
|
{Year: -508, Emperor: "鲁定公", Nianhao: "鲁定公", Dynasty: "鲁"},
|
||||||
|
{Year: -540, Emperor: "鲁昭公", Nianhao: "鲁昭公", Dynasty: "鲁"},
|
||||||
|
{Year: -571, Emperor: "鲁襄公", Nianhao: "鲁襄公", Dynasty: "鲁"},
|
||||||
|
{Year: -589, Emperor: "鲁成公", Nianhao: "鲁成公", Dynasty: "鲁"},
|
||||||
|
{Year: -607, Emperor: "鲁宣公", Nianhao: "鲁宣公", Dynasty: "鲁"},
|
||||||
|
{Year: -625, Emperor: "鲁文公", Nianhao: "鲁文公", Dynasty: "鲁"},
|
||||||
|
{Year: -658, Emperor: "鲁僖公", Nianhao: "鲁僖公", Dynasty: "鲁"},
|
||||||
|
{Year: -660, Emperor: "鲁闵公", Nianhao: "鲁闵公", Dynasty: "鲁"},
|
||||||
|
{Year: -692, Emperor: "鲁庄公", Nianhao: "鲁庄公", Dynasty: "鲁"},
|
||||||
|
{Year: -710, Emperor: "鲁桓公", Nianhao: "鲁桓公", Dynasty: "鲁"},
|
||||||
|
{Year: -721, Emperor: "鲁隐公", Nianhao: "鲁隐公", Dynasty: "鲁"},
|
||||||
|
{Year: -767, Emperor: "鲁惠公", Nianhao: "鲁惠公", Dynasty: "鲁"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var qinWarringAncientEras = []Era{
|
||||||
|
{Year: -245, Emperor: "秦王政", Nianhao: "秦王政", Dynasty: "秦"},
|
||||||
|
{Year: -248, Emperor: "秦庄襄王", Nianhao: "秦庄襄王", Dynasty: "秦"},
|
||||||
|
{Year: -249, Emperor: "秦孝文王", Nianhao: "秦孝文王", Dynasty: "秦"},
|
||||||
|
{Year: -305, Emperor: "秦昭襄王", Nianhao: "秦昭襄王", Dynasty: "秦"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var qinHanAncientEras = []Era{
|
||||||
|
{Year: -109, Emperor: "汉武帝", Nianhao: "元封", Dynasty: "西汉"},
|
||||||
|
{Year: -115, Emperor: "汉武帝", Nianhao: "元鼎", Dynasty: "西汉"},
|
||||||
|
{Year: -121, Emperor: "汉武帝", Nianhao: "元狩", Dynasty: "西汉"},
|
||||||
|
{Year: -127, Emperor: "汉武帝", Nianhao: "元朔", Dynasty: "西汉"},
|
||||||
|
{Year: -133, Emperor: "汉武帝", Nianhao: "元光", Dynasty: "西汉"},
|
||||||
|
{Year: -139, Emperor: "汉武帝", Nianhao: "建元", Dynasty: "西汉"},
|
||||||
|
{Year: -142, Emperor: "汉景帝", Nianhao: "后元", Dynasty: "西汉"},
|
||||||
|
{Year: -148, Emperor: "汉景帝", Nianhao: "中元", Dynasty: "西汉"},
|
||||||
|
{Year: -155, Emperor: "汉景帝", Nianhao: "前元", Dynasty: "西汉"},
|
||||||
|
{Year: -162, Emperor: "汉文帝", Nianhao: "后元", Dynasty: "西汉"},
|
||||||
|
{Year: -178, Emperor: "汉文帝", Nianhao: "前元", Dynasty: "西汉"},
|
||||||
|
{Year: -186, Emperor: "汉高后", Nianhao: "汉高后", Dynasty: "西汉"},
|
||||||
|
{Year: -193, Emperor: "汉惠帝", Nianhao: "汉惠帝", Dynasty: "西汉"},
|
||||||
|
{Year: -205, Emperor: "汉高祖", Nianhao: "汉高祖", Dynasty: "西汉"},
|
||||||
|
{Year: -208, Emperor: "秦二世", Nianhao: "秦二世", Dynasty: "秦"},
|
||||||
|
{Year: -245, Emperor: "秦始皇", Nianhao: "秦始皇", Dynasty: "秦"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func ancientErasForLunarYear(year int, system AncientCalendarSystem) []EraDesc {
|
||||||
|
switch system {
|
||||||
|
case AncientCalendarQinHan:
|
||||||
|
return ancientErasInRange(year, qinHanAncientEras, qinHanMinYear, qinHanMaxYear)
|
||||||
|
case AncientCalendarChunqiu, AncientCalendarLu:
|
||||||
|
return ancientErasInRange(year, luAncientEras, ancientBoundaryMinYear, -248)
|
||||||
|
case AncientCalendarZhuanxu:
|
||||||
|
if eras := ancientErasInRange(year, qinWarringAncientEras, -305, ancientBoundaryMaxYear); len(eras) > 0 {
|
||||||
|
return eras
|
||||||
|
}
|
||||||
|
return ancientErasInRange(year, zhouAncientEras, ancientBoundaryMinYear, -255)
|
||||||
|
case AncientCalendarZhou, AncientCalendarHuangdi, AncientCalendarYin, AncientCalendarXia1, AncientCalendarXia2:
|
||||||
|
return ancientErasInRange(year, zhouAncientEras, ancientBoundaryMinYear, -255)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ancientErasInRange(year int, eras []Era, min, max int) []EraDesc {
|
||||||
|
if len(eras) == 0 || year < min || year > max {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return innerEras(year, func() []Era { return eras })
|
||||||
|
}
|
||||||
|
|
||||||
|
func ancientEraSourcesForSystem(system AncientCalendarSystem) []ancientEraSource {
|
||||||
|
switch system {
|
||||||
|
case AncientCalendarDefault:
|
||||||
|
return []ancientEraSource{
|
||||||
|
{system: AncientCalendarQinHan, min: qinHanMinYear, max: qinHanMaxYear, eras: qinHanAncientEras},
|
||||||
|
{system: AncientCalendarChunqiu, min: ancientBoundaryMinYear, max: -480, eras: luAncientEras},
|
||||||
|
{system: AncientCalendarZhou, min: -479, max: -255, eras: zhouAncientEras},
|
||||||
|
}
|
||||||
|
case AncientCalendarQinHan:
|
||||||
|
return []ancientEraSource{{system: system, min: qinHanMinYear, max: qinHanMaxYear, eras: qinHanAncientEras}}
|
||||||
|
case AncientCalendarChunqiu, AncientCalendarLu:
|
||||||
|
return []ancientEraSource{{system: system, min: ancientBoundaryMinYear, max: -248, eras: luAncientEras}}
|
||||||
|
case AncientCalendarZhuanxu:
|
||||||
|
return []ancientEraSource{
|
||||||
|
{system: system, min: -305, max: ancientBoundaryMaxYear, eras: qinWarringAncientEras},
|
||||||
|
{system: system, min: ancientBoundaryMinYear, max: -255, eras: zhouAncientEras},
|
||||||
|
}
|
||||||
|
case AncientCalendarZhou, AncientCalendarHuangdi, AncientCalendarYin, AncientCalendarXia1, AncientCalendarXia2:
|
||||||
|
return []ancientEraSource{{system: system, min: ancientBoundaryMinYear, max: -255, eras: zhouAncientEras}}
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lunarToSolarAncientEra(data LunarTime, system AncientCalendarSystem) ([]Time, bool, error) {
|
||||||
|
sources := ancientEraSourcesForSystem(system)
|
||||||
|
if len(sources) == 0 {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
known := false
|
||||||
|
var results []Time
|
||||||
|
for _, source := range sources {
|
||||||
|
years, matched := ancientEraYears(source, data.comment, data.year)
|
||||||
|
if !matched {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
known = true
|
||||||
|
for _, year := range years {
|
||||||
|
times, err := lunarToSolarAncientEraYear(data, year, source.system)
|
||||||
|
if err == nil {
|
||||||
|
results = append(results, times...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !known {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
if len(results) == 0 {
|
||||||
|
return nil, true, fmt.Errorf("未找到对应日期")
|
||||||
|
}
|
||||||
|
return results, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ancientEraYears(source ancientEraSource, nianhao string, ordinal int) ([]int, bool) {
|
||||||
|
var years []int
|
||||||
|
matched := false
|
||||||
|
for idx, era := range source.eras {
|
||||||
|
if era.Nianhao != nianhao && era.Emperor != nianhao {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
matched = true
|
||||||
|
end := source.max
|
||||||
|
if idx > 0 && source.eras[idx-1].Year-1 < end {
|
||||||
|
end = source.eras[idx-1].Year - 1
|
||||||
|
}
|
||||||
|
year := era.Year + ordinal - 1 - era.Offset
|
||||||
|
if year >= source.min && year >= era.Year && year <= end {
|
||||||
|
years = append(years, year)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return years, matched
|
||||||
|
}
|
||||||
|
|
||||||
|
func lunarToSolarAncientEraYear(data LunarTime, year int, system AncientCalendarSystem) ([]Time, error) {
|
||||||
|
if data.houMonth && system != AncientCalendarQinHan && system != AncientCalendarZhuanxu {
|
||||||
|
return nil, fmt.Errorf("未找到对应日期")
|
||||||
|
}
|
||||||
|
if data.ganzhiMonth == "" || data.day != 0 {
|
||||||
|
result, err := LunarToSolarByYMDWithCalendar(year, data.month, data.day, data.leap, system)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return []Time{result}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var results []Time
|
||||||
|
for day := 1; day <= 30; day++ {
|
||||||
|
result, err := LunarToSolarByYMDWithCalendar(year, data.month, day, data.leap, system)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if GanZhiOfDay(result.Solar()) == data.ganzhiMonth {
|
||||||
|
results = append(results, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(results) == 0 {
|
||||||
|
return nil, fmt.Errorf("未找到对应日期")
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
@ -359,6 +359,16 @@ func innerParseLunar(lunar string) ([]time.Time, error) {
|
|||||||
return []time.Time{}, err
|
return []time.Time{}, err
|
||||||
}
|
}
|
||||||
if date.houMonth && date.comment != "" {
|
if date.houMonth && date.comment != "" {
|
||||||
|
if data, known, err := lunarToSolarAncientEra(date, AncientCalendarDefault); known {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var dates []time.Time
|
||||||
|
for _, v := range data {
|
||||||
|
dates = append(dates, v.Solar())
|
||||||
|
}
|
||||||
|
return dates, nil
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("未找到对应日期")
|
return nil, fmt.Errorf("未找到对应日期")
|
||||||
}
|
}
|
||||||
if date.year != 0 && date.comment == "" {
|
if date.year != 0 && date.comment == "" {
|
||||||
@ -427,6 +437,16 @@ func innerParseLunar(lunar string) ([]time.Time, error) {
|
|||||||
if tmp, err := innerLunar2SolarHanQing(date, nanMingEraMap, nanMingCals); err == nil {
|
if tmp, err := innerLunar2SolarHanQing(date, nanMingEraMap, nanMingCals); err == nil {
|
||||||
data = append(data, tmp...)
|
data = append(data, tmp...)
|
||||||
}
|
}
|
||||||
|
if date.comment != "" {
|
||||||
|
if ancientData, known, ancientErr := lunarToSolarAncientEra(date, AncientCalendarDefault); known {
|
||||||
|
if ancientErr != nil && len(data) == 0 {
|
||||||
|
return nil, ancientErr
|
||||||
|
}
|
||||||
|
for _, v := range ancientData {
|
||||||
|
data = append(data, v.Solar())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
if err == ERR_NIANHAO_NOT_FOUND {
|
if err == ERR_NIANHAO_NOT_FOUND {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -74,6 +74,7 @@ func qinHanTime(date time.Time, month qinHanMonth) Time {
|
|||||||
day: month.day,
|
day: month.day,
|
||||||
leap: month.leap,
|
leap: month.leap,
|
||||||
desc: formatQinHanLunarDateString(month.month, month.day, month.leap),
|
desc: formatQinHanLunarDateString(month.month, month.day, month.leap),
|
||||||
|
eras: ancientErasForLunarYear(month.lunarYear, AncientCalendarQinHan),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -509,10 +509,14 @@ func Test_ChineseCalendarAncientNegativeYearDescRoundtrip(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
descs := res.LunarDesc()
|
descs := res.LunarDesc()
|
||||||
if len(descs) != 1 || descs[0] != "负二五零年正月初一" {
|
if len(descs) != 1 || descs[0] != "前二五一年正月初一" {
|
||||||
t.Fatalf("unexpected descs: %v", descs)
|
t.Fatalf("unexpected descs: %v", descs)
|
||||||
}
|
}
|
||||||
for _, desc := range []string{descs[0], "負二五零年正月初一"} {
|
infos := res.LunarInfo()
|
||||||
|
if len(infos) != 1 || infos[0].LunarYearChn != "前二五一" || infos[0].EraDesc != "前二五一年" {
|
||||||
|
t.Fatalf("unexpected lunar info fallback: %#v", infos)
|
||||||
|
}
|
||||||
|
for _, desc := range []string{descs[0], "负二五零年正月初一", "負二五零年正月初一"} {
|
||||||
results, err := LunarToSolar(desc)
|
results, err := LunarToSolar(desc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(desc, err)
|
t.Fatal(desc, err)
|
||||||
@ -531,6 +535,80 @@ func Test_ChineseCalendarAncientNegativeYearDescRoundtrip(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ChineseCalendarAncientEra(t *testing.T) {
|
||||||
|
testData := []struct {
|
||||||
|
name string
|
||||||
|
system AncientCalendarSystem
|
||||||
|
lyear int
|
||||||
|
lmonth int
|
||||||
|
lday int
|
||||||
|
leap bool
|
||||||
|
want string
|
||||||
|
dynasty string
|
||||||
|
emperor string
|
||||||
|
nianhao string
|
||||||
|
eraYear int
|
||||||
|
}{
|
||||||
|
{name: "qin er shi third year", system: AncientCalendarQinHan, lyear: -206, lmonth: 10, lday: 1, want: "秦二世三年十月初一", dynasty: "秦", emperor: "秦二世", nianhao: "秦二世", eraYear: 3},
|
||||||
|
{name: "han gaozu first year", system: AncientCalendarQinHan, lyear: -205, lmonth: 10, lday: 1, want: "汉高祖元年十月初一", dynasty: "西汉", emperor: "汉高祖", nianhao: "汉高祖", eraYear: 1},
|
||||||
|
{name: "han jingdi zhongyuan first year", system: AncientCalendarQinHan, lyear: -148, lmonth: 1, lday: 1, want: "中元元年正月初一", dynasty: "西汉", emperor: "汉景帝", nianhao: "中元", eraYear: 1},
|
||||||
|
{name: "yuanfeng sixth leap ninth", system: AncientCalendarQinHan, lyear: -104, lmonth: 9, lday: 19, leap: true, want: "元封六年后九月十九", dynasty: "西汉", emperor: "汉武帝", nianhao: "元封", eraYear: 6},
|
||||||
|
{name: "zhou an wang", system: AncientCalendarZhou, lyear: -400, lmonth: 1, lday: 1, want: "周安王元年正月初一", dynasty: "周", emperor: "周安王", nianhao: "周安王", eraYear: 1},
|
||||||
|
{name: "lu ding gong", system: AncientCalendarChunqiu, lyear: -500, lmonth: 1, lday: 1, want: "鲁定公九年正月初一", dynasty: "鲁", emperor: "鲁定公", nianhao: "鲁定公", eraYear: 9},
|
||||||
|
}
|
||||||
|
for _, tc := range testData {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result, err := LunarToSolarByYMDWithCalendar(tc.lyear, tc.lmonth, tc.lday, tc.leap, tc.system)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
descs := result.LunarDesc()
|
||||||
|
if len(descs) != 1 || descs[0] != tc.want {
|
||||||
|
t.Fatalf("unexpected descs: %v", descs)
|
||||||
|
}
|
||||||
|
infos := result.LunarInfo()
|
||||||
|
if len(infos) != 1 {
|
||||||
|
t.Fatalf("unexpected info count: %#v", infos)
|
||||||
|
}
|
||||||
|
info := infos[0]
|
||||||
|
if info.Dynasty != tc.dynasty || info.Emperor != tc.emperor || info.Nianhao != tc.nianhao || info.YearOfNianhao != tc.eraYear {
|
||||||
|
t.Fatalf("unexpected era info: %#v", info)
|
||||||
|
}
|
||||||
|
if info.LunarWithEraDesc != tc.want {
|
||||||
|
t.Fatalf("unexpected lunar era desc: %q", info.LunarWithEraDesc)
|
||||||
|
}
|
||||||
|
parsed, err := LunarToSolarWithCalendar(tc.want, tc.system)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(parsed) != 1 || !parsed[0].Solar().Equal(result.Solar()) {
|
||||||
|
t.Fatalf("unexpected parsed result: %#v want %v", parsed, result.Solar())
|
||||||
|
}
|
||||||
|
defaultParsed, err := LunarToSolar(tc.want)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(defaultParsed) != 1 || !defaultParsed[0].Solar().Equal(result.Solar()) {
|
||||||
|
t.Fatalf("unexpected default parsed result: %#v want %v", defaultParsed, result.Solar())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
qinWang, err := LunarToSolarWithCalendar("秦王政元年十月初一", AncientCalendarZhuanxu)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qinWang) != 1 || qinWang[0].Lunar().LunarYear() != -245 || qinWang[0].Lunar().CalendarSystem() != AncientCalendarZhuanxu {
|
||||||
|
t.Fatalf("unexpected Qin Wang Zheng result: %#v", qinWang)
|
||||||
|
}
|
||||||
|
if _, err := LunarToSolar("秦王政元年十月初一"); err == nil {
|
||||||
|
t.Fatal("expected default parser to reject non-default Qin warring-state era")
|
||||||
|
}
|
||||||
|
if _, err := LunarToSolarWithCalendar("周安王元年后九月初一", AncientCalendarZhou); err == nil {
|
||||||
|
t.Fatal("expected non-Qin ancient era parser to reject hou month")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_ChineseCalendarAncientPreQin(t *testing.T) {
|
func Test_ChineseCalendarAncientPreQin(t *testing.T) {
|
||||||
testData := []struct {
|
testData := []struct {
|
||||||
name string
|
name string
|
||||||
@ -841,6 +919,8 @@ func TestHistoricalEraRegression(t *testing.T) {
|
|||||||
"祥兴元年正月初一",
|
"祥兴元年正月初一",
|
||||||
"贞祐元年正月初一",
|
"贞祐元年正月初一",
|
||||||
"贞佑元年正月初一",
|
"贞佑元年正月初一",
|
||||||
|
"前元元年正月初一",
|
||||||
|
"后元元年正月初一",
|
||||||
"嘉佑元年正月初一",
|
"嘉佑元年正月初一",
|
||||||
"元佑元年正月初一",
|
"元佑元年正月初一",
|
||||||
"天佑元年正月初一",
|
"天佑元年正月初一",
|
||||||
@ -853,6 +933,13 @@ func TestHistoricalEraRegression(t *testing.T) {
|
|||||||
t.Fatalf("LunarToSolar(%q) returned no candidates", tc)
|
t.Fatalf("LunarToSolar(%q) returned no candidates", tc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
houyuan, err := LunarToSolar("后元元年正月初一")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(houyuan) < 2 {
|
||||||
|
t.Fatalf("expected ancient and Han-Qing houyuan candidates, got %#v", houyuan)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -328,7 +328,7 @@ func (l LunarTime) innerDescWithNianHao(withEmperor bool, withDynasty bool) []st
|
|||||||
res = append(res, tmp)
|
res = append(res, tmp)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res = append(res, number2Chinese(l.year, true)+"年"+l.desc)
|
res = append(res, lunarYearDesc(l.year)+"年"+l.desc)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@ -343,7 +343,7 @@ func (l LunarTime) LunarInfo() []LunarInfo {
|
|||||||
li := LunarInfo{
|
li := LunarInfo{
|
||||||
SolarDate: l.solarDate,
|
SolarDate: l.solarDate,
|
||||||
LunarYear: l.year,
|
LunarYear: l.year,
|
||||||
LunarYearChn: number2Chinese(l.year, true),
|
LunarYearChn: lunarYearDesc(l.year),
|
||||||
LunarMonth: l.month,
|
LunarMonth: l.month,
|
||||||
LunarDay: l.day,
|
LunarDay: l.day,
|
||||||
IsLeap: l.leap,
|
IsLeap: l.leap,
|
||||||
@ -367,7 +367,7 @@ func (l LunarTime) LunarInfo() []LunarInfo {
|
|||||||
li := LunarInfo{
|
li := LunarInfo{
|
||||||
SolarDate: l.solarDate,
|
SolarDate: l.solarDate,
|
||||||
LunarYear: l.year,
|
LunarYear: l.year,
|
||||||
LunarYearChn: number2Chinese(l.year, true),
|
LunarYearChn: lunarYearDesc(l.year),
|
||||||
LunarMonth: l.month,
|
LunarMonth: l.month,
|
||||||
LunarDay: l.day,
|
LunarDay: l.day,
|
||||||
IsLeap: l.leap,
|
IsLeap: l.leap,
|
||||||
@ -381,11 +381,18 @@ func (l LunarTime) LunarInfo() []LunarInfo {
|
|||||||
Emperor: "",
|
Emperor: "",
|
||||||
Nianhao: "",
|
Nianhao: "",
|
||||||
YearOfNianhao: 0,
|
YearOfNianhao: 0,
|
||||||
EraDesc: number2Chinese(l.year, true) + "年",
|
EraDesc: lunarYearDesc(l.year) + "年",
|
||||||
LunarWithEraDesc: number2Chinese(l.year, true) + "年" + l.desc,
|
LunarWithEraDesc: lunarYearDesc(l.year) + "年" + l.desc,
|
||||||
ChineseZodiac: l.ShengXiao(),
|
ChineseZodiac: l.ShengXiao(),
|
||||||
}
|
}
|
||||||
res = append(res, li)
|
res = append(res, li)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lunarYearDesc(year int) string {
|
||||||
|
if year <= 0 {
|
||||||
|
return "前" + number2Chinese(1-year, true)
|
||||||
|
}
|
||||||
|
return number2Chinese(year, true)
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user