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