diff options
Diffstat (limited to 'src/calendar.cpp')
-rw-r--r-- | src/calendar.cpp | 234 |
1 files changed, 32 insertions, 202 deletions
diff --git a/src/calendar.cpp b/src/calendar.cpp index dcb96d7..9ad8413 100644 --- a/src/calendar.cpp +++ b/src/calendar.cpp | |||
@@ -2,226 +2,56 @@ | |||
2 | #include "calendar.h" | 2 | #include "calendar.h" |
3 | #include <cstdio> | 3 | #include <cstdio> |
4 | #include <ctime> | 4 | #include <ctime> |
5 | #include <iomanip> | ||
5 | 6 | ||
6 | /*以下为"calendar.h规定之量*/ | 7 | /*以下为"calendar.h规定之量*/ |
7 | double pi = 3.14159265358979323846; | ||
8 | double day = 86400; | 8 | double day = 86400; |
9 | double delta = 1e-11; | 9 | double delta = 1e-11; |
10 | char jieqi[25][10] = {"冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", | ||
11 | "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", | ||
12 | "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", | ||
13 | "立冬", "小雪", "大雪", "冬至"}; | ||
14 | 10 | ||
15 | /*计算需要用的类的实例化*/ | 11 | /*计算需要用的类的实例化*/ |
16 | Julian julian; | 12 | Julian julian; |
17 | parameter p; | 13 | parameter p; |
18 | List list; | ||
19 | 14 | ||
20 | Date *input(char *argv) { | 15 | void radToDMS(const char *message, int lowerBound, int upperBound, |
21 | Date *date = new Date; | 16 | double radians) { |
17 | // Convert radians to degrees | ||
18 | double degrees = radians * 180.0 / M_PI; | ||
22 | 19 | ||
23 | // 输入年份,自当年元旦起算 | 20 | while (degrees < lowerBound) |
24 | date->tm_year = atoi(argv) - 1900; | 21 | degrees += (upperBound - lowerBound); |
25 | date->tm_mon = 0; | 22 | while (degrees >= upperBound) |
26 | date->tm_mday = 1; | 23 | degrees -= (upperBound - lowerBound); |
27 | date->tm_hour = 0; | ||
28 | date->tm_min = 0; | ||
29 | date->tm_sec = 0; | ||
30 | 24 | ||
31 | return date; | 25 | // Calculate degrees, minutes, and seconds |
32 | } | 26 | int deg = static_cast<int>(degrees); |
33 | 27 | double min_sec = (degrees - deg) * 60.0; | |
34 | /*计算当年二十四节气时刻,自去年冬至到本年冬至*/ | 28 | int min = static_cast<int>(min_sec); |
35 | void JieQi(Date *date) { | 29 | double sec = (min_sec - min) * 60.0; |
36 | //计算起始时间为去年12月19日0时,开始寻找去年冬至 | ||
37 | time_t time = mktime(date); | ||
38 | time -= 13 * day; | ||
39 | |||
40 | double t, t_end, t_middle; //采用二分法计算,t与t_end为间隔24h的两个时刻 | ||
41 | double target_angle; //目标角度 | ||
42 | Date *date_tmp; | ||
43 | |||
44 | //计算每个节气对应太阳地心黄经 | ||
45 | for (int i = 0; i < 25; i++, time += 12 * day) { | ||
46 | target_angle = 15 * i + 270; | ||
47 | if (target_angle >= 360) | ||
48 | target_angle -= 360; | ||
49 | |||
50 | t = julian.getJulianKiloYear(time); | ||
51 | t_end = julian.getJulianKiloYear(time + day); | ||
52 | |||
53 | //定春分 | ||
54 | if (target_angle == 0) { | ||
55 | /* 春分太阳地心视黄经为0,一般二分法不便于计算 | ||
56 | * 因而限定范围为[355,360)∪(0,5],即春分前后各5度 | ||
57 | * 当t_end时刻太阳地心视黄经在[355,360)时,证明春分在后边,t和t_end前进24h | ||
58 | */ | ||
59 | while (p.sun_longitude(t_end) < 360 && | ||
60 | p.sun_longitude(t_end) > 355) { | ||
61 | time += day; | ||
62 | t = t_end; | ||
63 | t_end = julian.getJulianKiloYear(time + day); | ||
64 | } | ||
65 | /* 循环体time每次在已经计算出的上一节气基础上前进12日,理论上春分在t_end之后 | ||
66 | * 当跳出上一while循环时理论上春分时刻正在t与t_end之间 | ||
67 | * 为保险起见,添加这个循环 | ||
68 | * 当t时刻太阳地心视黄经在[0,5]时,证明春分在前边,t和t_end后退24h | ||
69 | */ | ||
70 | while (p.sun_longitude(t) < 5) { | ||
71 | time -= day; | ||
72 | t_end = t; | ||
73 | t = julian.getJulianKiloYear(time); | ||
74 | } | ||
75 | |||
76 | //二分法计算春分 | ||
77 | while (t_end - t > delta) { | ||
78 | t_middle = (t + t_end) / 2; | ||
79 | if (p.sun_longitude(t_middle) < 360 && | ||
80 | p.sun_longitude(t_middle) > 355) { | ||
81 | t = t_middle; | ||
82 | } else { | ||
83 | t_end = t_middle; | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | //其他情况 | ||
88 | else { | ||
89 | //当t_end时刻太阳地心视黄经小于目标角度,节气在后,t和t_end前进24h | ||
90 | while (p.sun_longitude(t_end) < target_angle) { | ||
91 | time += day; | ||
92 | t = t_end; | ||
93 | t_end = julian.getJulianKiloYear(time + day); | ||
94 | } | ||
95 | 30 | ||
96 | //当t时刻太阳地心视黄经大于目标角度,节气在前,t和t_end后退24h | 31 | // Output the result |
97 | //该循环也是一个保险循环 | 32 | printf("%s: %d°%d'%06.3f''\n", message, deg, min, sec); |
98 | while (p.sun_longitude(t) > target_angle) { | ||
99 | time -= day; | ||
100 | t_end = t; | ||
101 | t = julian.getJulianKiloYear(time); | ||
102 | } | ||
103 | |||
104 | while (t_end - t > delta) { | ||
105 | t_middle = (t + t_end) / 2; | ||
106 | if (p.sun_longitude(t_middle) < target_angle) { | ||
107 | t = t_middle; | ||
108 | } else { | ||
109 | t_end = t_middle; | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | //链表记录节气信息 | ||
115 | time = julian.kiloYearToTime(t, i == 0 ? date->tm_year + 1899 | ||
116 | : date->tm_year + 1900); | ||
117 | date_tmp = localtime(&time); | ||
118 | list.append(date_tmp, false, true, i % 2 == 0, i, t); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | // 用以判断朔日的函数,返回true则太阳地心黄经大于月球地心黄经,即朔日在此后 | ||
123 | bool date_forward(double sun_longitude, double moon_longitude) { | ||
124 | /* 判断逻辑 | ||
125 | * 当moon_longitude<sun_longitude时,由于时刻已经在朔日附近 | ||
126 | * 因而可以判断朔日在该时刻之后 | ||
127 | * 反之,当moon_longitude>sun_longitude时, | ||
128 | * 如果moon_longitude-sun_longitude<20,即度数相差不大,可知朔日在此前 | ||
129 | * 否则,大于20时候,度数相差过大,理论上只可能为moon_longitude已接近360,sun_longitude略微大于0 | ||
130 | * 此时实际上是月亮应当追赶太阳,因而朔日在此后 | ||
131 | */ | ||
132 | return moon_longitude < sun_longitude | ||
133 | ? true | ||
134 | : (moon_longitude - sun_longitude >= 20); | ||
135 | } | ||
136 | |||
137 | void ShuoRi(int year) { | ||
138 | double t, t_end, end, | ||
139 | t_middle; //采用二分法计算,t与t_end为间隔24h的两个时刻 | ||
140 | time_t time; | ||
141 | Date *date_tmp = new Date; | ||
142 | |||
143 | //根据zhongqi_vec的最后一项(今年冬至)计算冬至下一日的0时刻 | ||
144 | date_tmp->tm_year = list.zhongqi_vec[12]->year - 1900; | ||
145 | date_tmp->tm_mon = list.zhongqi_vec[12]->mon - 1; | ||
146 | date_tmp->tm_mday = list.zhongqi_vec[12]->day + 1; | ||
147 | date_tmp->tm_hour = 0; | ||
148 | date_tmp->tm_min = 0; | ||
149 | date_tmp->tm_sec = 0; | ||
150 | date_tmp->tm_isdst = -1; | ||
151 | time = mktime(date_tmp); | ||
152 | end = julian.getJulianKiloYear(time); | ||
153 | |||
154 | // 计算去年冬至时刻的time | ||
155 | date_tmp->tm_year = list.zhongqi_vec[0]->year - 1900; | ||
156 | date_tmp->tm_mon = list.zhongqi_vec[0]->mon - 1; | ||
157 | date_tmp->tm_mday = list.zhongqi_vec[0]->day; | ||
158 | date_tmp->tm_hour = list.zhongqi_vec[0]->hour; | ||
159 | date_tmp->tm_min = list.zhongqi_vec[0]->min; | ||
160 | date_tmp->tm_sec = list.zhongqi_vec[0]->sec; | ||
161 | date_tmp->tm_isdst = -1; | ||
162 | time = mktime(date_tmp); | ||
163 | |||
164 | delete date_tmp; | ||
165 | |||
166 | // 定朔日 | ||
167 | for (t = julian.getJulianKiloYear(time); t <= end; time += 25 * day) { | ||
168 | // 每月长度为28-30天,因而每次循环前进25天 | ||
169 | t = julian.getJulianKiloYear(time); | ||
170 | t_end = julian.getJulianKiloYear(time + day); | ||
171 | |||
172 | // 太阳在月亮之前,月亮追赶,故朔日在后,t和t_end前进24h | ||
173 | while (date_forward(p.sun_longitude(t_end), p.moon_longitude(t_end))) { | ||
174 | time += day; | ||
175 | t = t_end; | ||
176 | t_end = julian.getJulianKiloYear(time + day); | ||
177 | } | ||
178 | // 太阳在月亮之后,月亮落后,故朔日在前,t和t_end后退24h(用以保险) | ||
179 | while (!date_forward(p.sun_longitude(t), p.moon_longitude(t))) { | ||
180 | time -= day; | ||
181 | t_end = t; | ||
182 | t = julian.getJulianKiloYear(time); | ||
183 | } | ||
184 | |||
185 | while (t_end - t >= delta) { | ||
186 | t_middle = (t + t_end) / 2; | ||
187 | if (date_forward(p.sun_longitude(t_middle), | ||
188 | p.moon_longitude(t_middle))) { | ||
189 | t = t_middle; | ||
190 | } else { | ||
191 | t_end = t_middle; | ||
192 | } | ||
193 | } | ||
194 | // 输出朔日信息 | ||
195 | time = julian.kiloYearToTime(t, year - 1); | ||
196 | date_tmp = localtime(&time); | ||
197 | list.append(date_tmp, true, false, false, -1, t); | ||
198 | } | ||
199 | } | 33 | } |
200 | 34 | ||
201 | int main(int argc, char *argv[]) { | 35 | int main(int argc, char *argv[]) { |
202 | 36 | Date date; | |
203 | if (argc != 2) { | 37 | if (argc != 2) { |
204 | printf("Usage: %s year\\n\n", argv[0]); | 38 | printf("Input the time you want to calculate in <YYYY-MM-DD,HH:MM:SS> " |
205 | return 0; | 39 | "format: "); |
40 | scanf("%d-%d-%d,%d:%d:%d", &date.tm_year, &date.tm_mon, &date.tm_mday, | ||
41 | &date.tm_hour, &date.tm_min, &date.tm_sec); | ||
42 | } else { | ||
43 | sscanf(argv[1], "%d-%d-%d,%d:%d:%d", &date.tm_year, &date.tm_mon, | ||
44 | &date.tm_mday, &date.tm_hour, &date.tm_min, &date.tm_sec); | ||
206 | } | 45 | } |
207 | Date *date = input(argv[1]); | 46 | date.tm_year -= 1900; |
208 | int year = date->tm_year + 1900; | 47 | date.tm_mon -= 1; |
209 | double begin, end; | 48 | date.tm_isdst = -1; |
210 | |||
211 | JieQi(date); | ||
212 | ShuoRi(year); | ||
213 | |||
214 | list.lunar_sort(); | ||
215 | |||
216 | // 奉旨置闰 | ||
217 | list.Run(); | ||
218 | |||
219 | // 输出 | ||
220 | list.output(); | ||
221 | |||
222 | // 释放内存,使用List的析构函数 | ||
223 | 49 | ||
224 | delete date; | 50 | time_t time = mktime(&date); |
51 | double t = julian.getJulianKiloYear(time); | ||
225 | 52 | ||
53 | pair<double, double> sun = p.sun_longitude(t); | ||
54 | radToDMS("Sun longitude: ", 0, 360, sun.first); | ||
55 | radToDMS("Sun latitude: ", -90, 90, sun.second); | ||
226 | return 0; | 56 | return 0; |
227 | } | 57 | } |