-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathkaihuang.py
156 lines (131 loc) · 4.69 KB
/
kaihuang.py
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
#!/usr/bin/python3
# Convert between the Kaihuang calendar and Julian Day
from math import floor
from fractions import Fraction
from months import OLD_CHINESE as MONTHS, NUM_OLD_CHINESE as MONTHNO
sui = 365 + Fraction(25063, 102960) # tropical year
yue = 29 + Fraction(96529, 181920) # synodic month
zhongqi = sui / 12 # major solar term
solar_epoch = 1934351 + Fraction(775, 2574)
lunar_epoch = solar_epoch - Fraction(2218722317, 78043680)
def xinnian(year):
'''Compute New Year's Day of a given year'''
year = int(year)
if (year > 0):
year -= 1 # assuming there is no year 0
solstice = solar_epoch + (year * sui)
luns = (solstice - lunar_epoch) // yue
solmoon = lunar_epoch + (yue * luns) # solstice moon
while (floor(solmoon) > floor(solstice)):
solmoon -= yue
while (floor(solmoon + yue) <= floor(solstice)):
solmoon += yue
next_solstice = solstice + sui
next_moon = solmoon + (12 * yue)
if (floor(next_moon + yue) > floor(next_solstice)):
# no leap month here
ans = solmoon + (2 * yue)
else:
# there is a leap month somewhere
if ( (solmoon + (2 * yue) < solstice + zhongqi) or (solmoon + (3 * yue) < solstice + (2 * zhongqi)) ):
# leap month falls between the solstice and New Year's Day
ans = solmoon + (3 * yue)
else:
# leap month falls during the year to come
ans = solmoon + (2 * yue)
return ans
def lny(year):
'''Return the new moon of lunar new year, and whether the year is leap'''
year = int(year)
return ( xinnian(year), bool( (xinnian(year + 1) - xinnian(year)) / yue) )
def tojd(day, month, year):
'''Convert a date in the Kaihuang li to a Julian Day'''
day = int(day) - 1 # subtract 1 because computers count from 0
month = str(month)
year = int(year)
# account for the year
y = lny(year)
jday = y[0]
# account for the month
# first, did the user specify the leap month?
if (month[:3] == "Rùn"):
month = month[4:]
run = True
else:
run = False
if (not(y[1])):
# normal year
jday += (MONTHNO[month] * yue)
else:
# leap year
m = 0 # number of the month
l = False # have we passed the leap month?
z = solar_epoch + (year * sui) + (2 * zhongqi) # major solar term that the month contains
if (year > 0):
z -= sui
while( floor(z) < floor(jday) ):
z += zhongqi
while( floor(z - zhongqi) >= floor(jday) ):
z -= zhongqi
while (MONTHS[m] != month):
m += 1
jday += yue
if ( (not l) and (floor(jday + yue) < floor(z)) ):
# we have not yet past the leap month
l = True # now we are past the leap month
jday += yue
z += zhongqi
if ( run and (not l) and (floor(jday + (2 * yue)) < floor(z + zhongqi)) ):
# we are in the normal month, but the user specified the corresponding leap month
jday += yue
# compute the day
jday = floor(jday) + day
return jday
def fromjd(jday):
'''Convert a Julian Day into a date in the Kaihuang li'''
jday = int(jday)
# compute the year
year = (jday - solar_epoch) // sui
while (floor(xinnian(year)) > jday):
year -= 1
while (floor(xinnian(year + 1)) <= jday):
year += 1
# compute the month
y = lny(year)
xinyue = y[0]
if (not(y[1])):
# normal year
m = (jday - xinyue) // yue
while (floor(xinyue + yue) <= jday):
m += 1
xinyue += yue
month = MONTHS[m]
else:
# leap year
m = 0 # number of the month
l = False # have we passed the leap month?
z = solar_epoch + (year * sui) + (2 * zhongqi) # marker of the major solar term
if (year > 0):
z -= sui
while (floor(z) < floor(xinyue)):
z += zhongqi
while (floor(z - zhongqi) >= floor(xinyue)):
z -= zhongqi
while (floor(xinyue + yue) <= jday):
xinyue += yue
if(l):
m += 1
elif((not l) and (floor(xinyue) > floor(z))):
m += 1
z += zhongqi
else:
# this is the leap month
l = True
m -= 1 # the month has the same name as the previous month
month = MONTHS[m]
if ( (not l) and (floor(xinyue + yue) < floor(z)) ):
# it's the leap month
month = "Rùn " + month
# compute the day
day = jday - floor(xinyue) + 1 # add 1 because humans don't count from 0
return (day, month, year)