Home > Backend Development > Python Tutorial > How to share the method of converting solar calendar to lunar calendar in Python

How to share the method of converting solar calendar to lunar calendar in Python

黄舟
Release: 2017-08-22 13:14:50
Original
3061 people have browsed it

This article mainly introduces the method of converting the Gregorian calendar (solar calendar) to the lunar calendar (lunar calendar) in Python, involving the principles of the lunar calendar algorithm and Python date operation related operating skills. Friends in need can refer to the following

Examples of this article Python implements the method of converting the Gregorian calendar (solar calendar) to the lunar calendar (lunar calendar). Share it with everyone for your reference. The details are as follows:

Two important points:

1. The table lookup method is used to convert the Gregorian calendar to the lunar calendar (line 126)
2. Are astronomical methods used for solar terms? (Line 176)

Running chart (The background is hao123 perpetual calendar)

##Source code:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

# lunar.py

# 2015/02/27 罗兵

import datetime

class Lunar(object):

  #******************************************************************************

  # 下面为阴历计算所需的数据,为节省存储空间,所以采用下面比较变态的存储方法.

  #******************************************************************************

  #数组g_lunar_month_day存入阴历1901年到2050年每年中的月天数信息,

  #阴历每月只能是29或30天,一年用12(或13)个二进制位表示,对应位为1表30天,否则为29天

  g_lunar_month_day = [

    0x4ae0, 0xa570, 0x5268, 0xd260, 0xd950, 0x6aa8, 0x56a0, 0x9ad0, 0x4ae8, 0x4ae0,  #1910

    0xa4d8, 0xa4d0, 0xd250, 0xd548, 0xb550, 0x56a0, 0x96d0, 0x95b0, 0x49b8, 0x49b0,  #1920

    0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada8, 0x2b60, 0x9570, 0x4978, 0x4970, 0x64b0,  #1930

    0xd4a0, 0xea50, 0x6d48, 0x5ad0, 0x2b60, 0x9370, 0x92e0, 0xc968, 0xc950, 0xd4a0,  #1940

    0xda50, 0xb550, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950, 0xb4a8, 0x6ca0,  #1950

    0xb550, 0x55a8, 0x4da0, 0xa5b0, 0x52b8, 0x52b0, 0xa950, 0xe950, 0x6aa0, 0xad50,  #1960

    0xab50, 0x4b60, 0xa570, 0xa570, 0x5260, 0xe930, 0xd950, 0x5aa8, 0x56a0, 0x96d0,  #1970

    0x4ae8, 0x4ad0, 0xa4d0, 0xd268, 0xd250, 0xd528, 0xb540, 0xb6a0, 0x96d0, 0x95b0,  #1980

    0x49b0, 0xa4b8, 0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada0, 0xab60, 0x9370, 0x4978,  #1990

    0x4970, 0x64b0, 0x6a50, 0xea50, 0x6b28, 0x5ac0, 0xab60, 0x9368, 0x92e0, 0xc960,  #2000

    0xd4a8, 0xd4a0, 0xda50, 0x5aa8, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950,  #2010

    0xb4a0, 0xb550, 0xb550, 0x55a8, 0x4ba0, 0xa5b0, 0x52b8, 0x52b0, 0xa930, 0x74a8,  #2020

    0x6aa0, 0xad50, 0x4da8, 0x4b60, 0x9570, 0xa4e0, 0xd260, 0xe930, 0xd530, 0x5aa0,  #2030

    0x6b50, 0x96d0, 0x4ae8, 0x4ad0, 0xa4d0, 0xd258, 0xd250, 0xd520, 0xdaa0, 0xb5a0,  #2040

    0x56d0, 0x4ad8, 0x49b0, 0xa4b8, 0xa4b0, 0xaa50, 0xb528, 0x6d20, 0xada0, 0x55b0,  #2050

  ]

  #数组gLanarMonth存放阴历1901年到2050年闰月的月份,如没有则为0,每字节存两年

  g_lunar_month = [

    0x00, 0x50, 0x04, 0x00, 0x20,  #1910

    0x60, 0x05, 0x00, 0x20, 0x70,  #1920

    0x05, 0x00, 0x40, 0x02, 0x06,  #1930

    0x00, 0x50, 0x03, 0x07, 0x00,  #1940

    0x60, 0x04, 0x00, 0x20, 0x70,  #1950

    0x05, 0x00, 0x30, 0x80, 0x06,  #1960

    0x00, 0x40, 0x03, 0x07, 0x00,  #1970

    0x50, 0x04, 0x08, 0x00, 0x60,  #1980

    0x04, 0x0a, 0x00, 0x60, 0x05,  #1990

    0x00, 0x30, 0x80, 0x05, 0x00,  #2000

    0x40, 0x02, 0x07, 0x00, 0x50,  #2010

    0x04, 0x09, 0x00, 0x60, 0x04,  #2020

    0x00, 0x20, 0x60, 0x05, 0x00,  #2030

    0x30, 0xb0, 0x06, 0x00, 0x50,  #2040

    0x02, 0x07, 0x00, 0x50, 0x03  #2050

  ]

  START_YEAR = 1901

  # 天干

  gan = '甲乙丙丁戊己庚辛壬癸'

  # 地支

  zhi = '子丑寅卯辰巳午未申酉戌亥'

  # 生肖

  xiao = '鼠牛虎兔龙蛇马羊猴鸡狗猪'

  # 月份

  lm = '正二三四五六七八九十冬腊'

  # 日份

  ld = '初一初二初三初四初五初六初七初八初九初十十一十二十三十四十五十六十七十八十九二十廿一廿二廿三廿四廿五廿六廿七廿八廿九三十'

  # 节气

  jie = '小寒大寒立春雨水惊蛰春分清明谷雨立夏小满芒种夏至小暑大暑立秋处暑白露秋分寒露霜降立冬小雪大雪冬至'

  def __init__(self, dt = None):

    '''初始化:参数为datetime.datetime类实例,默认当前时间'''

    self.localtime = dt if dt else datetime.datetime.today()

  def sx_year(self): # 返回生肖年

    ct = self.localtime #取当前时间

    year = self.ln_year() - 3 - 1 # 农历年份减3 (说明:补减1)

    year = year % 12 # 模12,得到地支数

    return self.xiao[year]

  def gz_year(self): # 返回干支纪年

    ct = self.localtime #取当前时间

    year = self.ln_year() - 3 - 1 # 农历年份减3 (说明:补减1)

    G = year % 10 # 模10,得到天干数

    Z = year % 12 # 模12,得到地支数

    return self.gan[G] + self.zhi[Z]

  def gz_month(self): # 返回干支纪月(未实现)

    pass

  def gz_day(self): # 返回干支纪日

    ct = self.localtime #取当前时间

    C = ct.year // 100 #取世纪数,减一

    y = ct.year % 100 #取年份后两位(若为1月、2月则当前年份减一)

    y = y - 1 if ct.month == 1 or ct.month == 2 else y

    M = ct.month #取月份(若为1月、2月则分别按13、14来计算)

    M = M + 12 if ct.month == 1 or ct.month == 2 else M

    d = ct.day #取日数

    i = 0 if ct.month % 2 == 1 else 6 #取i (奇数月i=0,偶数月i=6)

    #下面两个是网上的公式

    # http://baike.baidu.com/link?url=MbTKmhrTHTOAz735gi37tEtwd29zqE9GJ92cZQZd0X8uFO5XgmyMKQru6aetzcGadqekzKd3nZHVS99rewya6q

    # 计算干(说明:补减1)

    G = 4 * C + C // 4 + 5 * y + y // 4 + 3 * (M + 1) // 5 + d - 3 - 1

    G = G % 10

    # 计算支(说明:补减1)

    Z = 8 * C + C // 4 + 5 * y + y // 4 + 3 * (M + 1) // 5 + d + 7 + i - 1

    Z = Z % 12

    #返回 干支纪日

    return self.gan[G] + self.zhi[Z]

  def gz_hour(self): # 返回干支纪时(时辰)

    ct = self.localtime #取当前时间

    #计算支

    Z = round((ct.hour/2) + 0.1) % 12 # 之所以加0.1是因为round的bug!!

    #返回 干支纪时(时辰)

    return self.zhi[Z]

  def ln_year(self): # 返回农历年

    year, _, _ = self.ln_date()

    return year

  def ln_month(self): # 返回农历月

    _, month, _ = self.ln_date()

    return month

  def ln_day(self): # 返回农历日

    _, _, day = self.ln_date()

    return day

  def ln_date(self): # 返回农历日期整数元组(年、月、日)(查表法)

    delta_days = self._date_diff()

    #阳历1901年2月19日为阴历1901年正月初一

    #阳历1901年1月1日到2月19日共有49天

    if (delta_days < 49):

      year = self.START_YEAR - 1

      if (delta_days <19):

       month = 11;

       day = 11 + delta_days

      else:

        month = 12;

        day = delta_days - 18

      return (year, month, day)

    #下面从阴历1901年正月初一算起

    delta_days -= 49

    year, month, day = self.START_YEAR, 1, 1

    #计算年

    tmp = self._lunar_year_days(year)

    while delta_days >= tmp:

      delta_days -= tmp

      year += 1

      tmp = self._lunar_year_days(year)

    #计算月

    (foo, tmp) = self._lunar_month_days(year, month)

    while delta_days >= tmp:

      delta_days -= tmp

      if (month == self._get_leap_month(year)):

        (tmp, foo) = self._lunar_month_days(year, month)

        if (delta_days < tmp):

          return (0, 0, 0)

          return (year, month, delta_days+1)

        delta_days -= tmp

      month += 1

      (foo, tmp) = self._lunar_month_days(year, month)

    #计算日

    day += delta_days

    return (year, month, day)

  def ln_date_str(self):# 返回农历日期字符串,形如:农历正月初九

    _, month, day = self.ln_date()

    return &#39;农历{}月{}&#39;.format(self.lm[month-1], self.ld[(day-1)*2:day*2])

  def ln_jie(self): # 返回农历节气

    ct = self.localtime #取当前时间

    year = ct.year

    for i in range(24):

      #因为两个都是浮点数,不能用相等表示

      delta = self._julian_day() - self._julian_day_of_ln_jie(year, i)

      if -.5 <= delta <= .5:

        return self.jie[i*2:(i+1)*2]

    return &#39;&#39;

  #显示日历

  def calendar(self):

    pass

  #######################################################

  #      下面皆为私有函数

  #######################################################

  def _date_diff(self):

    &#39;&#39;&#39;返回基于1901/01/01日差数&#39;&#39;&#39;

    return (self.localtime - datetime.datetime(1901, 1, 1)).days

  def _get_leap_month(self, lunar_year):

    flag = self.g_lunar_month[(lunar_year - self.START_YEAR) // 2]

    if (lunar_year - self.START_YEAR) % 2:

      return flag & 0x0f

    else:

      return flag >> 4

  def _lunar_month_days(self, lunar_year, lunar_month):

    if (lunar_year < self.START_YEAR):

      return 30

    high, low = 0, 29

    iBit = 16 - lunar_month;

    if (lunar_month > self._get_leap_month(lunar_year) and self._get_leap_month(lunar_year)):

      iBit -= 1

    if (self.g_lunar_month_day[lunar_year - self.START_YEAR] & (1 << iBit)):

      low += 1

    if (lunar_month == self._get_leap_month(lunar_year)):

      if (self.g_lunar_month_day[lunar_year - self.START_YEAR] & (1 << (iBit -1))):

         high = 30

      else:

         high = 29

    return (high, low)

  def _lunar_year_days(self, year):

    days = 0

    for i in range(1, 13):

      (high, low) = self._lunar_month_days(year, i)

      days += high

      days += low

    return days

  # 返回指定公历日期的儒略日

  def _julian_day(self):

    ct = self.localtime #取当前时间

    year = ct.year

    month = ct.month

    day = ct.day

    if month <= 2:

      month += 12

      year -= 1

    B = year / 100

    B = 2 - B + year / 400

    dd = day + 0.5000115740 #本日12:00后才是儒略日的开始(过一秒钟)*/

    return int(365.25 * (year + 4716) + 0.01) + int(30.60001 * (month + 1)) + dd + B - 1524.5

  # 返回指定年份的节气的儒略日数

  def _julian_day_of_ln_jie(self, year, st):

    s_stAccInfo =[

       0.00, 1272494.40, 2548020.60, 3830143.80, 5120226.60, 6420865.80,

       7732018.80, 9055272.60, 10388958.00, 11733065.40, 13084292.40, 14441592.00,

       15800560.80, 17159347.20, 18513766.20, 19862002.20, 21201005.40, 22529659.80,

       23846845.20, 25152606.00, 26447687.40, 27733451.40, 29011921.20, 30285477.60]

    #已知1900年小寒时刻为1月6日02:05:00

    base1900_SlightColdJD = 2415025.5868055555

    if (st < 0) or (st > 24):

      return 0.0

    stJd = 365.24219878 * (year - 1900) + s_stAccInfo[st] / 86400.0

    return base1900_SlightColdJD + stJd

# 测试

def test(ct=None):

  ln = Lunar(ct)

  print(&#39;公历 {} 北京时间 {}&#39;.format(ln.localtime.date(), ln.localtime.time()))

  print(&#39;{} 【{}】 {}年 {}日 {}时&#39;.format(ln.ln_date_str(), ln.gz_year(), ln.sx_year(), ln.gz_day(), ln.gz_hour()))

  print(&#39;节气:{}&#39;.format(ln.ln_jie()))

if __name__ == &#39;__main__&#39;:

  ct = datetime.datetime(2015,2,19,13,0,15)

  test(ct)

Copy after login

The above is the detailed content of How to share the method of converting solar calendar to lunar calendar in Python. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template