summaryrefslogtreecommitdiffstats
path: root/src/calendar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/calendar.cpp')
-rw-r--r--src/calendar.cpp234
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规定之量*/
7double pi = 3.14159265358979323846;
8double day = 86400; 8double day = 86400;
9double delta = 1e-11; 9double delta = 1e-11;
10char jieqi[25][10] = {"冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分",
11 "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑",
12 "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降",
13 "立冬", "小雪", "大雪", "冬至"};
14 10
15/*计算需要用的类的实例化*/ 11/*计算需要用的类的实例化*/
16Julian julian; 12Julian julian;
17parameter p; 13parameter p;
18List list;
19 14
20Date *input(char *argv) { 15void 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);
35void 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则太阳地心黄经大于月球地心黄经,即朔日在此后
123bool 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
137void 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
201int main(int argc, char *argv[]) { 35int 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}