carbon/calendar.lunar.go

433 lines
11 KiB
Go
Raw Normal View History

2021-07-08 09:47:25 +08:00
package carbon
import (
"fmt"
"strings"
)
var (
2021-07-31 13:42:53 +08:00
minYear, maxYear = 1900, 2100
chineseNumbers = []string{"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"}
chineseMonths = []string{"正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "腊"}
2021-07-12 16:20:47 +08:00
chineseDayPrefixes = []string{"初", "十", "廿", "卅"}
2021-08-02 10:18:38 +08:00
animals = []string{"猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"}
festivals = []string{"春节", "元宵节", "端午节", "七夕节", "中元节", "中秋节", "重阳节", "寒衣节", "下元节", "腊八节", "小年"}
2021-07-12 16:20:47 +08:00
lunarTerms = []int{
2021-07-08 09:47:25 +08:00
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, //1900-1909
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, //1910-1919
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, //1920-1929
2021-07-12 16:20:47 +08:00
0x06566, 0x0d4a0, 0x0ea50, 0x16a95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, //1930-1939
2021-07-08 09:47:25 +08:00
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, //1940-1949
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, //1950-1959
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, //1960-1969
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, //1970-1979
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, //1980-1989
2021-07-12 16:20:47 +08:00
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, //1990-1999
2021-07-08 09:47:25 +08:00
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, //2000-2009
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, //2010-2019
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, //2020-2029
0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, //2030-2039
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, //2040-2049
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, //2050-2059
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, //2060-2069
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, //2070-2079
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, //2080-2089
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, //2090-2099
0x0d520, //2100
}
2021-08-10 10:55:37 +08:00
invalidYearError = func(year int) error {
return fmt.Errorf("invalid year %d, currently only 200 years from 1900 to 2100 are supported", year)
}
2021-07-08 09:47:25 +08:00
)
2021-08-16 09:34:45 +08:00
// lunar defines a lunar struct.
2021-07-28 15:18:05 +08:00
// 定义 lunar 结构体
2021-07-08 09:47:25 +08:00
type lunar struct {
2021-07-13 16:42:21 +08:00
year, month, day int // 农历年、月、日
isLeapMonth bool // 是否是闰月
2021-08-10 10:55:37 +08:00
Error error
2021-07-08 09:47:25 +08:00
}
2021-08-16 09:34:45 +08:00
// Lunar converts the gregorian calendar to the lunar calendar.
2021-07-28 15:18:05 +08:00
// 将公历转为农历
2021-07-08 09:47:25 +08:00
func (c Carbon) Lunar() (l lunar) {
2021-07-23 10:48:37 +08:00
if c.IsInvalid() {
2021-08-10 10:55:37 +08:00
l.Error = c.Error
2021-07-23 10:48:37 +08:00
return
}
2021-07-08 09:47:25 +08:00
// leapMonths:闰月总数daysOfYear:年天数daysOfMonth:月天数leapMonth:闰月月份
daysInYear, daysInMonth, leapMonth := 365, 30, 0
2021-07-08 09:47:25 +08:00
// 有效范围检验
2022-04-12 17:16:21 +08:00
year := c.Year()
if year < minYear || year > maxYear {
l.Error = invalidYearError(year)
2021-07-08 09:47:25 +08:00
return
}
offset := int(c.DiffInDaysWithAbs(c.CreateFromDateTime(minYear, 1, 31, 0, 0, 0)))
2021-07-12 16:20:47 +08:00
for l.year = minYear; l.year <= maxYear && offset > 0; l.year++ {
2021-07-08 09:47:25 +08:00
daysInYear = l.getDaysInYear()
offset -= daysInYear
}
if offset < 0 {
offset += daysInYear
l.year--
}
l.isLeapMonth = false
leapMonth = l.LeapMonth()
for l.month = 1; l.month <= 12 && offset > 0; l.month++ {
if leapMonth > 0 && l.month == (leapMonth+1) && !l.isLeapMonth {
l.month--
l.isLeapMonth = true
daysInMonth = l.getDaysInLeapMonth()
} else {
daysInMonth = l.getDaysInMonth()
}
offset -= daysInMonth
if l.isLeapMonth && l.month == (leapMonth+1) {
l.isLeapMonth = false
}
}
// offset为0时并且刚才计算的月份是闰月要校正
if offset == 0 && leapMonth > 0 && l.month == leapMonth+1 {
if l.isLeapMonth {
l.isLeapMonth = false
} else {
l.isLeapMonth = true
l.month--
}
}
// offset小于0时也要校正
if offset < 0 {
offset += daysInMonth
l.month--
}
l.day = offset + 1
return
}
2021-08-10 10:55:37 +08:00
// getDaysInYear gets total days in lunar year.
2021-07-08 09:47:25 +08:00
// 获取该年总天数
func (l lunar) getDaysInYear() int {
2021-09-06 17:18:37 +08:00
var sum = 348
for i := 0x8000; i > 0x8; i >>= 1 {
2021-07-12 16:20:47 +08:00
if (lunarTerms[l.year-minYear] & i) != 0 {
2021-07-08 09:47:25 +08:00
sum++
}
}
return sum + l.getDaysInLeapMonth()
2021-07-08 09:47:25 +08:00
}
2021-08-10 10:55:37 +08:00
// getDaysInMonth gets total days in lunar month.
2021-07-28 15:18:05 +08:00
// 获取该月总天数
2021-07-08 09:47:25 +08:00
func (l lunar) getDaysInMonth() int {
2021-07-12 16:20:47 +08:00
if (lunarTerms[l.year-minYear] & (0x10000 >> uint(l.month))) == 0 {
2021-07-08 09:47:25 +08:00
return 29
}
return 30
}
2021-08-10 10:55:37 +08:00
// getDaysInLeapMonth gets total days in lunar leap month.
2021-07-28 15:18:05 +08:00
// 获取闰月总天数
2021-07-08 09:47:25 +08:00
func (l lunar) getDaysInLeapMonth() int {
if l.LeapMonth() == 0 {
return 0
}
2021-07-12 16:20:47 +08:00
if (lunarTerms[l.year-minYear] & 0x10000) != 0 {
2021-07-08 09:47:25 +08:00
return 30
}
return 29
}
2021-08-10 10:55:37 +08:00
// Animal gets lunar animal name.
2021-07-28 15:18:05 +08:00
// 获取生肖
2021-07-08 09:47:25 +08:00
func (l lunar) Animal() string {
if l.year == 0 {
return ""
}
return animals[l.year%MonthsPerYear]
}
2021-09-08 13:40:41 +08:00
// Festival gets lunar festival name.
2021-07-28 15:18:05 +08:00
// 获取农历节日
2021-07-12 16:20:47 +08:00
func (l lunar) Festival() string {
if l.year == 0 {
return ""
}
switch {
case l.month == 1 && l.day == 1:
2021-09-06 17:18:37 +08:00
return festivals[0]
2021-07-12 16:20:47 +08:00
case l.month == 1 && l.day == 15:
2021-09-06 17:18:37 +08:00
return festivals[1]
2021-07-12 16:20:47 +08:00
case l.month == 5 && l.day == 5:
2021-09-06 17:18:37 +08:00
return festivals[2]
2021-07-12 16:20:47 +08:00
case l.month == 7 && l.day == 7:
2021-09-06 17:18:37 +08:00
return festivals[3]
2021-07-12 16:20:47 +08:00
case l.month == 7 && l.day == 15:
2021-09-06 17:18:37 +08:00
return festivals[4]
2021-07-12 16:20:47 +08:00
case l.month == 8 && l.day == 15:
2021-09-06 17:18:37 +08:00
return festivals[5]
2021-07-12 16:20:47 +08:00
case l.month == 9 && l.day == 9:
2021-09-06 17:18:37 +08:00
return festivals[6]
2021-07-12 16:20:47 +08:00
case l.month == 10 && l.day == 1:
2021-09-06 17:18:37 +08:00
return festivals[7]
2021-07-12 16:20:47 +08:00
case l.month == 10 && l.day == 15:
2021-09-06 17:18:37 +08:00
return festivals[8]
2021-07-12 16:20:47 +08:00
case l.month == 12 && l.day == 8:
2021-09-06 17:18:37 +08:00
return festivals[9]
2021-07-12 16:20:47 +08:00
case l.month == 12 && l.day == 23:
2021-09-06 17:18:37 +08:00
return festivals[10]
2021-07-12 16:20:47 +08:00
}
2021-09-06 17:18:37 +08:00
return ""
2021-07-12 16:20:47 +08:00
}
2021-08-10 10:55:37 +08:00
// Year gets lunar year.
2021-07-28 15:18:05 +08:00
// 获取农历年
2021-07-08 09:47:25 +08:00
func (l lunar) Year() int {
return l.year
}
2021-08-10 10:55:37 +08:00
// Month gets lunar month.
2021-07-28 15:18:05 +08:00
// 获取农历月
2021-07-08 09:47:25 +08:00
func (l lunar) Month() int {
return l.month
}
2021-09-16 09:52:35 +08:00
// LeapMonth gets lunar leap month.
2021-07-28 15:18:05 +08:00
//获取农历闰月月份
2021-07-08 09:47:25 +08:00
func (l lunar) LeapMonth() int {
if l.year == 0 {
return 0
}
return lunarTerms[l.year-minYear] & 0xf
2021-07-08 09:47:25 +08:00
}
2021-09-08 13:40:41 +08:00
// Day gets lunar day.
2021-07-28 15:18:05 +08:00
// 获取农历日
2021-07-08 09:47:25 +08:00
func (l lunar) Day() int {
return l.day
}
2021-08-10 10:55:37 +08:00
// ToYearString outputs a string in lunar year format.
2021-07-28 15:18:05 +08:00
// 获取农历年字符串
2021-07-13 16:42:21 +08:00
func (l lunar) ToYearString() string {
2021-07-08 09:47:25 +08:00
if l.year == 0 {
return ""
}
year := fmt.Sprintf("%d", l.year)
2021-07-12 16:20:47 +08:00
for i, replace := range chineseNumbers {
2021-07-08 09:47:25 +08:00
year = strings.Replace(year, fmt.Sprintf("%d", i), replace, -1)
}
return year
}
2021-08-10 10:55:37 +08:00
// ToMonthString outputs a string in lunar month format.
2021-07-28 15:18:05 +08:00
// 获取农历月字符串
2021-07-13 16:42:21 +08:00
func (l lunar) ToMonthString() string {
2021-07-08 09:47:25 +08:00
if l.month == 0 {
return ""
}
2021-07-13 16:42:21 +08:00
return chineseMonths[l.month-1]
2021-07-08 09:47:25 +08:00
}
2021-08-10 10:55:37 +08:00
// ToDayString outputs a string in lunar day format.
2021-07-28 15:18:05 +08:00
// 获取农历日字符串
2021-07-13 16:42:21 +08:00
func (l lunar) ToDayString() string {
2021-07-08 09:47:25 +08:00
if l.day == 0 {
return ""
}
day := ""
switch l.day {
case 10:
day = "初十"
case 20:
day = "二十"
case 30:
day = "三十"
default:
2021-07-12 16:20:47 +08:00
day = chineseDayPrefixes[(l.day/10)] + chineseNumbers[l.day%10]
2021-07-08 09:47:25 +08:00
}
return day
}
2022-04-12 17:16:21 +08:00
// ToDateString outputs a string in lunar date format.
// 获取农历日期字符串
func (l lunar) ToDateString() string {
if l.year == 0 {
return ""
}
return l.ToYearString() + "年" + l.ToMonthString() + "月" + l.ToDayString()
}
2021-08-10 10:55:37 +08:00
// String outputs a string in YYYY-MM-DD format, implement Stringer interface.
// 输出 YYYY-MM-DD 格式字符串, 实现 Stringer 接口
func (l lunar) String() string {
if l.year == 0 {
return ""
}
return fmt.Sprintf("%d-%02d-%02d", l.year, l.month, l.day)
}
2021-09-16 09:52:35 +08:00
// IsLeapYear reports whether is leap year.
2021-07-28 15:18:05 +08:00
// 是否是闰年
2021-07-08 09:47:25 +08:00
func (l lunar) IsLeapYear() bool {
2021-07-10 15:50:17 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
return l.LeapMonth() != 0
}
2021-09-16 09:52:35 +08:00
// IsLeapMonth reports whether is leap month.
2021-07-28 15:18:05 +08:00
// 是否是闰月
2021-07-08 09:47:25 +08:00
func (l lunar) IsLeapMonth() bool {
if l.month == 0 {
return false
}
return l.month == l.LeapMonth()
}
2021-09-16 09:52:35 +08:00
// IsRatYear reports whether is year of Rat.
2021-07-28 15:18:05 +08:00
// 是否是鼠年
2021-07-12 16:20:47 +08:00
func (l lunar) IsRatYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 4 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsOxYear reports whether is year of Ox.
2021-07-28 15:18:05 +08:00
// 是否是牛年
2021-07-12 16:20:47 +08:00
func (l lunar) IsOxYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 5 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsTigerYear reports whether is year of Tiger.
2021-07-28 15:18:05 +08:00
// 是否是虎年
2021-07-12 16:20:47 +08:00
func (l lunar) IsTigerYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 6 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsRabbitYear reports whether is year of Rabbit.
2021-07-28 15:18:05 +08:00
// 是否是兔年
2021-07-12 16:20:47 +08:00
func (l lunar) IsRabbitYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 7 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsDragonYear reports whether is year of Dragon.
2021-07-28 15:18:05 +08:00
// 是否是龙年
2021-07-12 16:20:47 +08:00
func (l lunar) IsDragonYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 8 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsSnakeYear reports whether is year of Snake.
2021-07-28 15:18:05 +08:00
// 是否是蛇年
2021-07-12 16:20:47 +08:00
func (l lunar) IsSnakeYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 9 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsHorseYear reports whether is year of Horse.
2021-07-28 15:18:05 +08:00
// 是否是马年
2021-07-12 16:20:47 +08:00
func (l lunar) IsHorseYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 10 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsGoatYear reports whether is year of Goat.
2021-07-28 15:18:05 +08:00
// 是否是羊年
2021-07-12 16:20:47 +08:00
func (l lunar) IsGoatYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 11 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsMonkeyYear reports whether is year of Monkey.
2021-07-28 15:18:05 +08:00
// 是否是猴年
2021-07-12 16:20:47 +08:00
func (l lunar) IsMonkeyYear() bool {
2021-07-08 09:47:25 +08:00
if l.year == 0 {
return false
}
if l.year%MonthsPerYear == 0 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsRoosterYear reports whether is year of Rooster.
2021-07-28 15:18:05 +08:00
// 是否是鸡年
2021-07-12 16:20:47 +08:00
func (l lunar) IsRoosterYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 1 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsDogYear reports whether is year of Dog.
2021-07-28 15:18:05 +08:00
// 是否是狗年
2021-07-12 16:20:47 +08:00
func (l lunar) IsDogYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 2 {
return true
}
return false
}
2021-09-16 09:52:35 +08:00
// IsPigYear reports whether is year of Pig.
2021-07-28 15:18:05 +08:00
// 是否是猪年
2021-07-12 16:20:47 +08:00
func (l lunar) IsPigYear() bool {
2021-07-10 14:21:27 +08:00
if l.year == 0 {
return false
}
2021-07-08 09:47:25 +08:00
if l.year%MonthsPerYear == 3 {
return true
}
return false
}